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);
    }

}

性能

3536.两个数字的最大乘积

目标

给定一个正整数 n。

返回 任意两位数字 相乘所得的 最大 乘积。

注意:如果某个数字在 n 中出现多次,你可以多次使用该数字。

示例 1:

输入: n = 31
输出: 3
解释:
n 的数字是 [3, 1]。
任意两位数字相乘的结果为:3 * 1 = 3。
最大乘积为 3。

示例 2:

输入: n = 22
输出: 4
解释:
n 的数字是 [2, 2]。
任意两位数字相乘的结果为:2 * 2 = 4。
最大乘积为 4。

示例 3:

输入: n = 124
输出: 8
解释:
n 的数字是 [1, 2, 4]。
任意两位数字相乘的结果为:1 * 2 = 2, 1 * 4 = 4, 2 * 4 = 8。
最大乘积为 8。

说明:

  • 10 <= n <= 10^9

思路

给定一个数字 n,选择数位中的两个数字相乘,返回乘积的最大值。

找到最大的两个数字相乘即可。

代码


/**
 * @date 2026-07-27 14:22
 */
public class MaxProduct3536 {

    public int maxProduct(int n) {
        int max = 0;
        int preMax = 0;
        int res = 0;
        while (n > 0) {
            int d = n % 10;
            if (d >= preMax) {
                preMax = Math.min(max, d);
                max = Math.max(max, d);
                res = Math.max(res, max * preMax);
            }
            n /= 10;
        }
        return res;
    }

}

性能

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;
    }

}

性能

3513.不同 XOR 三元组的数目I

目标

给你一个长度为 n 的整数数组 nums,其中 nums 是范围 [1, n] 内所有数的 排列 。

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

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

排列 是一个集合中所有元素的重新排列。

示例 1:

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

示例 2:

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

说明:

  • 1 <= n == nums.length <= 10^5
  • 1 <= nums[i] <= n
  • nums 是从 1 到 n 的整数的一个排列。

思路

有一个 1 ~ n 的排列,从中取三个数(可重复)的异或值 XOR,求不同的 XOR 值有多少个。

可以构造出 0 ~ 2^(k + 1) - 1 之间的任意数字,其中 k 是从右向左的最高位(从 0 开始)。

代码


/**
 * @date 2026-07-23 9:55
 */
public class UniqueXorTriplets3513 {

    public int uniqueXorTriplets(int[] nums) {
        int n = nums.length;
        return n <= 2 ? n : 1 << (32 - Integer.numberOfLeadingZeros(n));
    }
}

性能

3501.操作后最大活跃区段数II

目标

给你一个长度为 n 的二进制字符串 s ,其中:

  • '1' 表示一个 活跃 区段。
  • '0' 表示一个 非活跃 区段。

你最多可以进行一次 操作 来最大化 s 中活跃区段的数量。在一次操作中,你可以:

  • 将一个被 '0' 包围的连续 '1' 区块转换为全 '0'。
  • 然后,将一个被 '1' 包围的连续 '0' 区块转换为全 '1'。

此外,你还有一个 二维数组 queries,其中 queries[i] = [li, ri] 表示子字符串 s[li...ri]。

对于每个查询,确定在对子字符串 s[li...ri] 进行最优交换后,字符串 s 中 可能的最大 活跃区段数。

返回一个数组 answer,其中 answer[i] 是 queries[i] 的结果。

注意

  • 对于每个查询,仅对 s[li...ri] 处理时,将其看作是在两端都加上一个 '1' 后的字符串,形成 t = '1' + s[li...ri] + '1'。这些额外的 '1' 不会对最终的活跃区段数有贡献。
  • 各个查询相互独立。

示例 1:

输入: s = "01", queries = [[0,1]]
输出: [1]
解释:

因为没有被 '0' 包围的 '1' 区块,所以没有有效的操作可以进行。最大活跃区段数是 1。

示例 2:

输入: s = "0100", queries = [[0,3],[0,2],[1,3],[2,3]]
输出: [4,3,1,1]
解释:

查询 [0, 3] → 子字符串 "0100" → 变为 "101001"
选择 "0100","0100" → "0000" → "1111"。
最终字符串(去掉添加的 '1')为 "1111"。最大活跃区段数为 4。

查询 [0, 2] → 子字符串 "010" → 变为 "10101"
选择 "010","010" → "000" → "111"。
最终字符串(去掉添加的 '1')为 "1110"。最大活跃区段数为 3。

查询 [1, 3] → 子字符串 "100" → 变为 "11001"
因为没有被 '0' 包围的 '1' 区块,所以没有有效的操作可以进行。最大活跃区段数为 1。

查询 [2, 3] → 子字符串 "00" → 变为 "1001"
因为没有被 '0' 包围的 '1' 区块,所以没有有效的操作可以进行。最大活跃区段数为 1。

示例 3:

输入: s = "1000100", queries = [[1,5],[0,6],[0,4]]
输出: [6,7,2]
解释:

查询 [1, 5] → 子字符串 "00010" → 变为 "1000101"
选择 "00010","00010" → "00000" → "11111"。
最终字符串(去掉添加的 '1')为 "1111110"。最大活跃区段数为 6。

查询 [0, 6] → 子字符串 "1000100" → 变为 "110001001"
选择 "000100","000100" → "000000" → "111111"。
最终字符串(去掉添加的 '1')为 "1111111"。最大活跃区段数为 7。

查询 [0, 4] → 子字符串 "10001" → 变为 "1100011"
因为没有被 '0' 包围的 '1' 区块,所以没有有效的操作可以进行。最大活跃区段数为 2。

示例 4:

输入: s = "01010", queries = [[0,3],[1,4],[1,3]]
输出: [4,4,2]
解释:

查询 [0, 3] → 子字符串 "0101" → 变为 "101011"
选择 "010","010" → "000" → "111"。
最终字符串(去掉添加的 '1')为 "11110"。最大活跃区段数为 4。

查询 [1, 4] → 子字符串 "1010" → 变为 "110101"
选择 "010","010" → "000" → "111"。
最终字符串(去掉添加的 '1')为 "01111"。最大活跃区段数为 4。

查询 [1, 3] → 子字符串 "101" → 变为 "11011"
因为没有被 '0' 包围的 '1' 区块,所以没有有效的操作可以进行。最大活跃区段数为 2。

说明:

  • 1 <= n == s.length <= 10^5
  • 1 <= queries.length <= 10^5
  • s[i] 只有 '0' 或 '1'。
  • queries[i] = [li, ri]
  • 0 <= li <= ri < n

思路

// todo

代码

性能

3499.操作后最大活跃区段数I

目标

给你一个长度为 n 的二进制字符串 s,其中:

  • '1' 表示一个 活跃 区段。
  • '0' 表示一个 非活跃 区段。

你可以执行 最多一次操作 来最大化 s 中的活跃区段数量。在一次操作中,你可以:

  • 将一个被 '0' 包围的连续 '1' 区块转换为全 '0'。
  • 然后,将一个被 '1' 包围的连续 '0' 区块转换为全 '1'。

返回在执行最优操作后,s 中的 最大 活跃区段数。

注意:处理时需要在 s 的两侧加上 '1' ,即 t = '1' + s + '1'。这些加上的 '1' 不会影响最终的计数。

示例 1:

输入: s = "01"
输出: 1
解释:
因为没有被 '0' 包围的 '1' 区块,因此无法进行有效操作。最大活跃区段数为 1。

示例 2:

输入: s = "0100"
输出: 4
解释:
字符串 "0100" → 两端加上 '1' 后得到 "101001" 。
选择 "0100","101001" → "100001" → "111111" 。
最终的字符串去掉两端的 '1' 后为 "1111" 。最大活跃区段数为 4。

示例 3:

输入: s = "1000100"
输出: 7
解释:
字符串 "1000100" → 两端加上 '1' 后得到 "110001001" 。
选择 "000100","110001001" → "110000001" → "111111111"。
最终的字符串去掉两端的 '1' 后为 "1111111"。最大活跃区段数为 7。

示例 4:

输入: s = "01010"
输出: 4
解释:
字符串 "01010" → 两端加上 '1' 后得到 "1010101"。
选择 "010","1010101" → "1000101" → "1111101"。
最终的字符串去掉两端的 '1' 后为 "11110"。最大活跃区段数为 4。

说明:

  • 1 <= n == s.length <= 10^5
  • s[i] 仅包含 '0' 或 '1'

思路

有一个二进制字符串,在其首尾拼上 1,然后执行一次操作:将一个被 0 包围的连续 1 全部转为 0,然后将一个被 1 包围的连续 0 全部转为 1,求操作之后 字符串1 的最大个数(不包括首尾拼接的 1)。

实际上是求字符串中 1 两侧连续 0 的最大长度。

判断 01 分界,记录之前连续 0 的个数与当前连续 0 的个数之和的最大值。

代码


/**
 * @date 2026-07-21 10:41
 */
public class MaxActiveSectionsAfterTrade3499 {

    public int maxActiveSectionsAfterTrade(String s) {
        int n = s.length();
        int prevZero = 0;
        int curZero = 0;
        int oneCnt = 0;
        int max = 0;
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == '1') {
                oneCnt++;
                if (curZero > 0) {
                    if (prevZero > 0) {
                        max = Math.max(max, curZero + prevZero);
                    }
                    prevZero = curZero;
                    curZero = 0;
                }
            } else {
                curZero++;
            }
        }
        if (curZero > 0) {
            if (prevZero > 0) {
                max = Math.max(max, curZero + prevZero);
            }
        }
        return oneCnt + max;
    }

}

性能

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;
    }
}

性能

3658.奇数和与偶数和的最大公约数

目标

给你一个整数 n。请你计算以下两个值的 最大公约数(GCD):

sumOdd:最小的 n 个正奇数的总和。

sumEven:最小的 n 个正偶数的总和。

返回 sumOdd 和 sumEven 的 GCD。

示例 1:

输入: n = 4
输出: 4
解释:
前 4 个奇数的总和 sumOdd = 1 + 3 + 5 + 7 = 16
前 4 个偶数的总和 sumEven = 2 + 4 + 6 + 8 = 20
因此,GCD(sumOdd, sumEven) = GCD(16, 20) = 4。

示例 2:

输入: n = 5
输出: 5
解释:
前 5 个奇数的总和 sumOdd = 1 + 3 + 5 + 7 + 9 = 25
前 5 个偶数的总和 sumEven = 2 + 4 + 6 + 8 + 10 = 30
因此,GCD(sumOdd, sumEven) = GCD(25, 30) = 5。

提示:

1 <= n <= 1000

思路

计算最小的 n 个正奇数的和与最小的 n 个正偶数和的最大公约数。

  • (1 + 3 + 5 + …… + 2n - 1) = 2n * n / 2 = n^2
  • (2 + 4 + 6 + …… + 2n) = (2n + 2) * n / 2 = n * (n + 1)

最大公约数为 n

代码


/**
 * @date 2026-07-15 8:51
 */
public class GcdOfOddEvenSums3658 {

    public int gcdOfOddEvenSums(int n) {
        int oddSum = 0;
        int evenSum = 0;
        for (int k = 0, i = 1, j = 2; k < n; i += 2, j += 2, k++) {
            oddSum += i;
            evenSum += j;
        }
        return gcd(oddSum, evenSum);
    }

    public int gcd(int a, int b) {
        if (b == 0) {
            return a;
        }
        return gcd(b, a % b);
    }

}

性能

1291.顺次数

目标

我们定义「顺次数」为:每一位上的数字都比前一位上的数字大 1 的整数。

请你返回由 [low, high] 范围内所有顺次数组成的 有序 列表(从小到大排序)。

示例 1:

输出:low = 100, high = 300
输出:[123,234]

示例 2:

输出:low = 1000, high = 13000
输出:[1234,2345,3456,4567,5678,6789,12345]

说明:

  • 10 <= low <= high <= 10^9

思路

定义顺序数字为从左到右每一位都比前一位的数字大 1 的整数。返回 [low, high] 范围内的所有顺序数字,按从小到大返回。

枚举数字长度以及开头数字,判断生成的顺序数字是否在 [low, high] 内即可。

代码


/**
 * @date 2026-07-13 9:10
 */
public class SequentialDigits1291 {

    public List<Integer> sequentialDigits(int low, int high) {
        int l = Integer.toString(low).length();
        int r = Integer.toString(high).length();
        List<Integer> res = new ArrayList<>();
        for (int i = l; i <= r; i++) {
            for(int j = 1; j + i <= 10; j++){
                Integer num = genInteger(j, i);
                if (low <= num && num <= high){
                    res.add(num);
                }
            }
        }
        return res;
    }

    public Integer genInteger(int first, int length) {
        int res = 0;
        for (int i = 0; i < length && first < 10; i++) {
            res = res * 10 + first;
            first++;
        }
        return res;
    }

}

性能