3483.不同三位偶数的数目

目标

给你一个数字数组 digits,你需要从中选择三个数字组成一个三位偶数,你的任务是求出 不同 三位偶数的数量。

注意:每个数字在三位偶数中都只能使用 一次 ,并且 不能 有前导零。

示例 1:

输入: digits = [1,2,3,4]
输出: 12
解释: 可以形成的 12 个不同的三位偶数是 124,132,134,142,214,234,312,314,324,342,412 和 432。注意,不能形成 222,因为数字 2 只有一个。

示例 2:

输入: digits = [0,2,2]
输出: 2
解释: 可以形成的三位偶数是 202 和 220。注意,数字 2 可以使用两次,因为数组中有两个 2 。

示例 3:

输入: digits = [6,6,6]
输出: 1
解释: 只能形成 666。

示例 4:

输入: digits = [1,3,5]
输出: 0
解释: 无法形成三位偶数。

说明:

  • 3 <= digits.length <= 10
  • 0 <= digits[i] <= 9

思路

有一个数字数组 digits,数组元素为 0 ~ 9 ,从中选择 3 个组成一个三位偶数,求不同的三位偶数的个数。

从结果来考虑,三位数 100 ~ 999,针对每个数字判断能否由数组中的数字构成即可。

从构造的角度考虑,需要保证个位是偶数,且百位不是 0,要求数字不同,需要维护可用的数字种类,需要知道每个数字的已使用次数,可以使用回溯。

代码


/**
 * @date 2026-09-11 8:56
 */
public class TotalNumbers3483 {

    public int totalNumbers(int[] digits) {
        int[] d = new int[10];
        for (int num : digits) {
            d[num]++;
        }
        int res = 0;
        for (int num = 100; num < 999; num += 2) {
            if (valid(num, d)) {
                res++;
            }
        }
        return res;
    }

    public boolean valid(int num, int[] d) {
        int[] tmp = new int[10];
        while (num > 0) {
            tmp[num % 10]++;
            num /= 10;
        }
        for (int i = 0; i < 10; i++) {
            if (d[i] < tmp[i]) {
                return false;
            }
        }
        return true;
    }

    public int totalNumbers_v0(int[] digits) {
        int[] d = new int[10];
        for (int num : digits) {
            d[num]++;
        }
        int res = 0;
        // 枚举百位
        for (int i = 1; i < d.length; i++) {
            if (d[i] == 0) {
                continue;
            }
            d[i]--;
            res += dfs(0, i, d);
            d[i]++;
        }

        return res;
    }

    int dfs(int index, int num, int[] d) {
        if (index == 2) {
            // 第三个数如果是偶数返回 1
            return num % 2 == 0 ? 1 : 0;
        }
        int res = 0;
        // 枚举十位
        for (int i = 0; i < d.length; i++) {
            if (d[i] == 0) {
                continue;
            }
            d[i]--;
            res += dfs(index + 1, i, d);
            d[i]++;
        }
        return res;
    }

}

性能

3904.最小稳定下标II

目标

给你一个长度为 n 的整数数组 nums 和一个整数 k。

对于每个下标 i,定义它的 不稳定值 为 max(nums[0..i]) - min(nums[i..n - 1])。

换句话说:

  • max(nums[0..i]) 表示从下标 0 到下标 i 的元素中的 最大值 。
  • min(nums[i..n - 1]) 表示从下标 i 到下标 n - 1 的元素中的 最小值 。

如果某个下标 i 的不稳定值 小于等于 k,则称该下标为 稳定下标 。

返回 最小 的稳定下标。如果不存在这样的下标,则返回 -1。

示例 1:

输入: nums = [5,0,1,4], k = 3
输出: 3
解释:
在下标 0 处:[5] 中的最大值是 5,[5, 0, 1, 4] 中的最小值是 0,因此不稳定值为 5 - 0 = 5。
在下标 1 处:[5, 0] 中的最大值是 5,[0, 1, 4] 中的最小值是 0,因此不稳定值为 5 - 0 = 5。
在下标 2 处:[5, 0, 1] 中的最大值是 5,[1, 4] 中的最小值是 1,因此不稳定值为 5 - 1 = 4。
在下标 3 处:[5, 0, 1, 4] 中的最大值是 5,[4] 中的最小值是 4,因此不稳定值为 5 - 4 = 1。
这是第一个不稳定值小于等于 k = 3 的下标,因此答案是 3。

示例 2:

输入: nums = [3,2,1], k = 1
输出: -1
解释:
在下标 0 处,不稳定值为 3 - 1 = 2。
在下标 1 处,不稳定值为 3 - 1 = 2。
在下标 2 处,不稳定值为 3 - 1 = 2。
这些值都不小于等于 k = 1,因此答案是 -1。

示例 3:

输入: nums = [0], k = 0
输出: 0
解释:
在下标 0 处,不稳定值为 0 - 0 = 0,它小于等于 k = 0。因此答案是 0。

说明:

  • 1 <= nums.length <= 10^5
  • 0 <= nums[i] <= 10^9
  • 0 <= k <= 10^9

思路

3903.最小稳定下标I 相比数据范围扩大了。

代码


/**
 * @date 2026-09-07 9:01
 */
public class FirstStableIndex3904 {

    public int firstStableIndex(int[] nums, int k) {
        int n = nums.length;
        int[] suffix = new int[n + 1];
        Arrays.fill(suffix, Integer.MAX_VALUE);
        for (int i = n - 1; i >= 0; i--) {
            suffix[i] = Math.min(suffix[i + 1], nums[i]);
        }
        int max = 0;
        for (int i = 0; i < n; i++) {
            max = Math.max(max, nums[i]);
            if (max - suffix[i] <= k) {
                return i;
            }
        }
        return -1;
    }
}

性能

3903.最小稳定下标I

目标

给你一个长度为 n 的整数数组 nums 和一个整数 k。

对于每个下标 i,定义它的 不稳定值 为 max(nums[0..i]) - min(nums[i..n - 1])。

换句话说:

  • max(nums[0..i]) 表示从下标 0 到下标 i 的元素中的 最大值 。
  • min(nums[i..n - 1]) 表示从下标 i 到下标 n - 1 的元素中的 最小值 。

如果某个下标 i 的不稳定值 小于等于 k,则称该下标为 稳定下标 。

返回 最小 的稳定下标。如果不存在这样的下标,则返回 -1。

示例 1:

输入: nums = [5,0,1,4], k = 3
输出: 3
解释:
在下标 0 处:[5] 中的最大值是 5,[5, 0, 1, 4] 中的最小值是 0,因此不稳定值为 5 - 0 = 5。
在下标 1 处:[5, 0] 中的最大值是 5,[0, 1, 4] 中的最小值是 0,因此不稳定值为 5 - 0 = 5。
在下标 2 处:[5, 0, 1] 中的最大值是 5,[1, 4] 中的最小值是 1,因此不稳定值为 5 - 1 = 4。
在下标 3 处:[5, 0, 1, 4] 中的最大值是 5,[4] 中的最小值是 4,因此不稳定值为 5 - 4 = 1。
这是第一个不稳定值小于等于 k = 3 的下标,因此答案是 3。

示例 2:

输入: nums = [3,2,1], k = 1
输出: -1
解释:
在下标 0 处,不稳定值为 3 - 1 = 2。
在下标 1 处,不稳定值为 3 - 1 = 2。
在下标 2 处,不稳定值为 3 - 1 = 2。
这些值都不小于等于 k = 1,因此答案是 -1。

示例 3:

输入: nums = [0], k = 0
输出: 0
解释:
在下标 0 处,不稳定值为 0 - 0 = 0,它小于等于 k = 0。因此答案是 0。

说明:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 10^9
  • 0 <= k <= 10^9

思路

定义下标 i 的不稳定值为 max(nums[0..i]) - min(nums[i..n - 1]),如果该值小于等于 k 则称 i 为稳定下标。返回最小的稳定下标。

前后缀分解,计算后缀最小值,从左到右枚举,记录前缀最大值,如果满足条件直接返回,否则返回 -1

代码


/**
 * @date 2026-09-04 9:14
 */
public class FirstStableIndex3903 {

    public int firstStableIndex(int[] nums, int k) {
        int n = nums.length;
        int[] suffix = new int[n + 1];
        Arrays.fill(suffix, Integer.MAX_VALUE);
        for (int i = n - 1; i >= 0; i--) {
            suffix[i] = Math.min(suffix[i + 1], nums[i]);
        }
        int max = 0;
        for (int i = 0; i < n; i++) {
            max = Math.max(max, nums[i]);
            if (max - suffix[i] <= k) {
                return i;
            }
        }
        return -1;
    }

}

性能

3876.构造奇偶一致的数组II

目标

给你一个长度为 n 的数组 nums1,其中包含 互不相同 的整数。

你需要构造另一个长度为 n 的数组 nums2,使得 nums2 中的元素要么全部为 奇数,要么全部为 偶数。

对于每个下标 i,你必须从以下两种选择中 任选其一(顺序不限):

  • nums2[i] = nums1[i]
  • nums2[i] = nums1[i] - nums1[j],其中 j != i,且满足 nums1[i] - nums1[j] >= 1

如果能够构造出满足条件的数组,则返回 true;否则,返回 false。

示例 1:

输入: nums1 = [1,4,7]
输出: true
解释:
设置 nums2[0] = nums1[0] = 1。
设置 nums2[1] = nums1[1] - nums1[0] = 4 - 1 = 3。
设置 nums2[2] = nums1[2] = 7。
nums2 = [1, 3, 7],所有元素均为奇数。因此答案为 true。

示例 2:

输入: nums1 = [2,3]
输出: false
解释:
无法构造出满足所有元素奇偶性相同的 nums2。因此答案为 false。

示例 3:

输入: nums1 = [4,6]
输出: true
解释:
设置 nums2[0] = nums1[0] = 4。
设置 nums2[1] = nums1[1] = 6。
nums2 = [4, 6],所有元素均为偶数。因此答案为 true。

说明:

  • 1 <= n == nums1.length <= 10^5
  • 1 <= nums1[i] <= 10^9
  • nums1 中的所有整数互不相同。

思路

有一个元素互不相同的整数数组 nums1,问能否构造另一个相同长度的数组 nums2nums2[i] = nums1[i] 或者 nums2[i] = nums1[i] - nums1[j],其中 j != i && nums1[i] - nums1[j] >= 1。使得 nums2 中的元素全为 奇数偶数

本题加了一个限制,只能减去比自身小的数。减去一个偶数不会改变奇偶性,还得考虑奇数。

如果全为奇数或偶数返回 true,枚举奇数与偶数的最小值,如果奇数最小值小于偶数最小值则返回 true

代码


/**
 * @date 2026-09-03 10:08
 */
public class UniformArray3876 {

    public boolean uniformArray(int[] nums1) {
        int oddMin = Integer.MAX_VALUE;
        int evenMin = Integer.MAX_VALUE;
        for (int num : nums1) {
            if (num % 2 == 0) {
                evenMin = Math.min(num, evenMin);
            } else {
                oddMin = Math.min(num, oddMin);
            }
        }
        if (oddMin == Integer.MAX_VALUE || evenMin == Integer.MAX_VALUE) {
            return true;
        }
        return oddMin < evenMin;
    }
}

性能

3875.构造奇偶一致的数组I

目标

给你一个长度为 n 的数组 nums1,其中包含 互不相同 的整数。

你需要构造另一个长度为 n 的数组 nums2,使得 nums2 中的元素要么全部为 奇数,要么全部为 偶数。

对于每个下标 i,你必须从以下两种选择中 任选其一(顺序不限):

  • nums2[i] = nums1[i]
  • nums2[i] = nums1[i] - nums1[j],其中 j != i

如果能够构造出满足条件的数组,则返回 true;否则,返回 false。

示例 1:

输入: nums1 = [2,3]
输出: true
解释:
    选择 nums2[0] = nums1[0] - nums1[1] = 2 - 3 = -1。
    选择 nums2[1] = nums1[1] = 3。
    nums2 = [-1, 3],两个元素均为奇数。因此答案为 true。

示例 2:

输入: nums1 = [4,6]
输出: true
解释:​​​​​​​
    选择 nums2[0] = nums1[0] = 4。
    选择 nums2[1] = nums1[1] = 6。
    nums2 = [4, 6],两个元素均为偶数。因此答案为 true。

说明:

  • 1 <= n == nums1.length <= 100
  • 1 <= nums1[i] <= 100
  • nums1 中的所有整数互不相同。

思路

有一个元素互不相同的整数数组 nums1,问能否构造另一个相同长度的数组 nums2nums2[i] = nums1[i] 或者 nums2[i] = nums1[i] - nums1[j],其中 j != i。使得 nums2 中的元素全为 奇数偶数

如果数组元素均为奇数/偶数直接满足条件,否则,可以将偶数减去任意奇数,使得整个数组变为奇数。直接返回 true 即可。

代码


/**
 * @date 2026-09-02 9:17
 */
public class UniformArray3875 {

    public boolean uniformArray(int[] nums1) {
        return true;
    }
}

性能

2996.大于等于顺序前缀和的最小缺失整数

目标

给你一个下标从 0 开始的整数数组 nums 。

如果一个前缀 nums[0..i] 满足对于 1 <= j <= i 的所有元素都有 nums[j] = nums[j - 1] + 1 ,那么我们称这个前缀是一个 顺序前缀 。特殊情况是,只包含 nums[0] 的前缀也是一个 顺序前缀 。

请你返回 nums 中没有出现过的 最小 整数 x ,满足 x 大于等于 最长 顺序前缀的和。

示例 1:

输入:nums = [1,2,3,2,5]
输出:6
解释:nums 的最长顺序前缀是 [1,2,3] ,和为 6 ,6 不在数组中,所以 6 是大于等于最长顺序前缀和的最小整数。

示例 2:

输入:nums = [3,4,5,1,12,14,13]
输出:15
解释:nums 的最长顺序前缀是 [3,4,5] ,和为 12 ,12、13 和 14 都在数组中,但 15 不在,所以 15 是大于等于最长顺序前缀和的最小整数。

说明:

  • 1 <= nums.length <= 50
  • 1 <= nums[i] <= 50

思路

定义数组 nums 的顺序前缀是满足 1 <= j <= i, nums[j] = nums[j - 1] + 1 的前缀,返回大于等于数组顺序前缀和且没有出现在数组的最小整数。

使用哈希表保存数组所有元素,计算顺序前缀和 sum,从 sum 返回第一个不在哈希表中的整数即可。

代码


/**
 * @date 2026-08-11 8:58
 */
public class MissingInteger2996 {

    public int missingInteger(int[] nums) {
        int n = nums.length;
        if (n == 1) {
            return nums[0] + 1;
        }
        Set<Integer> set = Arrays.stream(nums).boxed().collect(Collectors.toSet());
        int sum = nums[0];
        for (int i = 1; i < n; i++) {
            if (nums[i] != nums[i - 1] + 1) {
                break;
            }
            sum += nums[i];
        }
        while (set.contains(sum)) {
            sum++;
        }
        return sum;
    }
}

性能

1464.数组中两元素的最大乘积

目标

给你一个整数数组 nums,请你选择数组的两个不同下标 i 和 j,使 (nums[i]-1)*(nums[j]-1) 取得最大值。

请你计算并返回该式的最大值。

示例 1:

输入:nums = [3,4,5,2]
输出:12 
解释:如果选择下标 i=1 和 j=2(下标从 0 开始),则可以获得最大值,(nums[1]-1)*(nums[2]-1) = (4-1)*(5-1) = 3*4 = 12 。 

示例 2:

输入:nums = [1,5,4,5]
输出:16
解释:选择下标 i=1 和 j=3(下标从 0 开始),则可以获得最大值 (5-1)*(5-1) = 16 。

示例 3:

输入:nums = [3,7]
输出:12

说明:

  • 2 <= nums.length <= 500
  • 1 <= nums[i] <= 10^3

思路

从数组中取两个不同下标的元素相乘并返回最大的乘积。

找到数组最大的两个元素相乘即可。

代码


/**
 * @date 2026-07-27 8:55
 */
public class MaxProduct1464 {

    public int maxProduct(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        return (nums[n - 1] - 1) * (nums[n - 2] - 1);
    }
}

性能

628.三个数的最大乘积

目标

给你一个整型数组 nums ,在数组中找出由三个数组成的最大乘积,并输出这个乘积。

示例 1:

输入:nums = [1,2,3]
输出:6

示例 2:

输入:nums = [1,2,3,4]
输出:24

示例 3:

输入:nums = [-1,-2,-3]
输出:-6

说明:

  • 3 <= nums.length <= 10^4
  • -1000 <= nums[i] <= 1000

思路

从数组中取三个不同的下标,返回其乘积的最大值。

由于存在负数,分情况讨论,定义 max1max2max3 分别为前三大元素,min1min2 分别是前二小元素:

  • 如果 max1 < 0, 乘积只能为负,要使乘积最大,那么其绝对值应该最小,因此取 max1 * max2 * max3
  • 如果 max2 < 0, 最大乘积可以为正,取最小的两个负数相乘,乘积最大,取 max1 * min1 * min2
  • 如果 max3 < 0,乘积可能为正也可能为负(只有三个元素),不论那种情况,都可取 max1 * min1 * min2
  • 如果 max3 > 0, 最大值可能是 max1 * max2 * max3 或者 max1 * min1 * min2

代码


/**
 * @date 2026-07-27 16:37
 */
public class MaximumProduct628 {

    public int maximumProduct_v1(int[] nums) {
        int max1 = -1001, max2 = -1001, max3 = -1001;
        int min1 = 1001, min2 = 1001;
        for (int num : nums) {
            if (num > max1) {
                max3 = max2;
                max2 = max1;
                max1 = num;
            } else if (num > max2) {
                max3 = max2;
                max2 = num;
            } else if (num > max3) {
                max3 = num;
            }
            if (num < min1) {
                min2 = min1;
                min1 = num;
            } else if (num < min2) {
                min2 = num;
            }
        }
        return Math.max(max1 * max2 * max3, max1 * min1 * min2);
    }

}

性能

3514.不同 XOR 三元组的数目II

目标

给你一个整数数组 nums 。

XOR 三元组 定义为三个元素的异或值 nums[i] XOR nums[j] XOR nums[k],其中 i <= j <= k。

返回所有可能三元组 (i, j, k) 中 不同 的 XOR 值的数量。

示例 1:

输入: nums = [1,3]
输出: 2
解释:
所有可能的 XOR 三元组值为:
(0, 0, 0) → 1 XOR 1 XOR 1 = 1
(0, 0, 1) → 1 XOR 1 XOR 3 = 3
(0, 1, 1) → 1 XOR 3 XOR 3 = 1
(1, 1, 1) → 3 XOR 3 XOR 3 = 3
不同的 XOR 值为 {1, 3} 。因此输出为 2 。

示例 2:

输入: nums = [6,7,8,9]
输出: 4
解释:
不同的 XOR 值为 {6, 7, 8, 9} 。因此输出为 4 。

说明:

1 <= nums.length <= 1500
1 <= nums[i] <= 1500

思路

有一个正整数数组 nums,从中取三个数(可重复)的异或值 XOR,求不同的 XOR 值有多少个。

暴力枚举。

代码


/**
 * @date 2026-07-24 9:12
 */
public class UniqueXorTriplets3514 {

    public int uniqueXorTriplets(int[] nums) {
        int n = nums.length;
        int max = 0;
        for (int num : nums) {
            max = Math.max(max, num);
        }
        int upper = 1 << (32 - Integer.numberOfLeadingZeros(max));
        boolean[] tmp = new boolean[upper];
        boolean[] arr = new boolean[upper];
        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                tmp[nums[i] ^ nums[j]] = true;
            }
        }
        for (int i = 0; i < upper; i++) {
            if (tmp[i]) {
                for (int num : nums) {
                    arr[num ^ i] = true;
                }
            }
        }
        int res = 0;
        for (boolean b : arr) {
            if (b) {
                res++;
            }
        }
        return res;
    }

}

性能

3867.数对的最大公约数之和

目标

给你一个长度为 n 的整数数组 nums。

构造一个数组 prefixGcd,其中对于每个下标 i:

  • 令 mxi = max(nums[0], nums[1], ..., nums[i])。
  • prefixGcd[i] = gcd(nums[i], mxi)。

在构造 prefixGcd 之后:

  • 将 prefixGcd 按 非递减 顺序排序。
  • 通过取 最小的未配对 元素和 最大的未配对 元素来形成数对。
  • 重复此过程,直到无法再形成更多数对。
  • 对于每个形成的数对,计算 两个元素的最大公约数 gcd。
  • 如果 n 是奇数,prefixGcd 数组中的 中间 元素保持 未配对 状态,并应被忽略。

返回一个整数,表示所有形成数对的 最大公约数之和。

术语 gcd(a, b) 表示 a 和 b 的 最大公约数。

示例 1:

输入: nums = [2,6,4]
输出: 2
解释:
构造 prefixGcd:
i nums[i] mxi prefixGcd[i]
0    2    2      2
1    6    6      6
2    4    6      2
prefixGcd = [2, 6, 2]。排序后形成 [2, 2, 6]。
将最小和最大的元素配对:gcd(2, 6) = 2。剩下的中间元素 2 被忽略。因此,总和为 2。

示例 2:

输入: nums = [3,6,2,8]
输出: 5
解释:
构造 prefixGcd:
i nums[i] mxi prefixGcd[i]
0    3     3      3
1    6     6      6
2    2     6      2
3    8     8      8
prefixGcd = [3, 6, 2, 8]。排序后形成 [2, 3, 6, 8]。
形成数对:gcd(2, 8) = 2 和 gcd(3, 6) = 3。因此,总和为 2 + 3 = 5。

说明:

  • 1 <= n == nums.length <= 10^5
  • 1 <= nums[i] <= 10^9

思路

有一个正整数数组 nums,构造数组 prefixGcdprefixGcd[i] = gcd(maxi, nums[i]),其中 maxi[0, i] 的最大值。将 prefixGcd 排序后首尾配对,忽略中间未配对元素,求每对 gcd 之和。

根据题目模拟即可。

代码


/**
 * @date 2026-07-16 9:34
 */
public class GcdSum3867 {

    public long gcdSum(int[] nums) {
        int n = nums.length;
        int[] prefixGcd = new int[n];
        int max = 0;
        for (int i = 0; i < n; i++) {
            max = Math.max(max, nums[i]);
            prefixGcd[i] = gcd(max, nums[i]);
        }
        Arrays.sort(prefixGcd);
        long res = 0;
        int l = 0, r = n - 1;
        while (l < r) {
            res += gcd(prefixGcd[l++], prefixGcd[r--]);
        }
        return res;
    }

    public int gcd(int a, int b) {
        while (b != 0) {
            int tmp = b;
            b = a % b;
            a = tmp;
        }
        return a;
    }
}

性能