3644.排序排列

目标

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

你可以在满足条件 nums[i] AND nums[j] == k 的情况下交换下标 i 和 j 的元素,其中 AND 表示按位与操作,k 是一个非负整数。

返回可以使数组按 非递减 顺序排序的最大值 k(允许进行任意次这样的交换)。如果 nums 已经是有序的,返回 0。

排列 是数组所有元素的一种重新排列。

示例 1:

输入:nums = [0,3,2,1]
输出:1
解释:
选择 k = 1。交换 nums[1] = 3 和 nums[3] = 1,因为 nums[1] AND nums[3] == 1,从而得到一个排序后的排列:[0, 1, 2, 3]。

示例 2:

输入:nums = [0,1,3,2]
输出:2
解释:
选择 k = 2。交换 nums[2] = 3 和 nums[3] = 2,因为 nums[2] AND nums[3] == 2,从而得到一个排序后的排列:[0, 1, 2, 3]。

示例 3:

输入:nums = [3,2,1,0]
输出:0
解释:
只有当 k = 0 时,才能进行排序,因为没有更大的 k 能够满足 nums[i] AND nums[j] == k 的交换条件。

说明:

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

思路

有一个 0 ~ n - 1 的排列 nums,如果 nums[i] & nums[j] == k,则允许交换元素 nums[i] 与 nums[j]。返回使得 nums 递增所允许的最大的 k,如果排列本来就是有序的返回 0。

任何数与 0 相与都是 0,如果想交换元素 nums[i] 和 nums[j],可以将元素 0 作为中间元素来交换,一定有解。

所有不在位置上的元素都是需要交换的,k 就是这些元素相与的结果,无论怎么排列,只是相与的顺序不同,结果是一样的。

代码


/**
 * @date 2026-10-23 9:06
 */
public class SortPermutation3644 {

    public int sortPermutation(int[] nums) {
        int n = nums.length;
        int res = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            if (nums[i] != i) {
                res &= nums[i];
            }
        }
        return res == Integer.MAX_VALUE ? 0 : res;
    }

}

性能

2089.找出数组排序后的目标下标

目标

给你一个下标从 0 开始的整数数组 nums 以及一个目标元素 target 。

目标下标 是一个满足 nums[i] == target 的下标 i 。

将 nums 按 非递减 顺序排序后,返回由 nums 中目标下标组成的列表。如果不存在目标下标,返回一个 空 列表。返回的列表必须按 递增 顺序排列。

示例 1:

输入:nums = [1,2,5,2,3], target = 2
输出:[1,2]
解释:排序后,nums 变为 [1,2,2,3,5] 。
满足 nums[i] == 2 的下标是 1 和 2 。

示例 2:

输入:nums = [1,2,5,2,3], target = 3
输出:[3]
解释:排序后,nums 变为 [1,2,2,3,5] 。
满足 nums[i] == 3 的下标是 3 。

示例 3:

输入:nums = [1,2,5,2,3], target = 5
输出:[4]
解释:排序后,nums 变为 [1,2,2,3,5] 。
满足 nums[i] == 5 的下标是 4 。

示例 4:

输入:nums = [1,2,5,2,3], target = 4
输出:[]
解释:nums 中不含值为 4 的元素。

说明:

  • 1 <= nums.length <= 100
  • 1 <= nums[i], target <= 100

思路

有一个下标从 0 开始的数组 nums,从中查找值为 target 的元素,返回其在排序后的数组中的下标,如果没有找到返回空。

直接的想法是先排序数组,然后遍历查找目标,将下标加入结果集,时间复杂度为 O(nlogn)。

本题只关心特定元素在数组中的位次,只需统计左右两端的元素数目即可算出下标。

代码


/**
 * @date 2026-10-19 8:48
 */
public class TargetIndices2089 {

    public List<Integer> targetIndices(int[] nums, int target) {
        int n = nums.length;
        int l = 0, r = 0;
        List<Integer> res = new ArrayList<>();
        for (int num : nums) {
            if (num < target) {
                l++;
            } else if (num > target) {
                r++;
            }
        }
        int length = n - l - r;
        for (int i = 0; i < length; i++) {
            res.add(l++);
        }
        return res;
    }
}

性能

2913.子数组不同元素数目的平方和I

目标

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

定义 nums 一个子数组的 不同计数 值如下:

  • 令 nums[i..j] 表示 nums 中所有下标在 i 到 j 范围内的元素构成的子数组(满足 0 <= i <= j < nums.length ),那么我们称子数组 nums[i..j] 中不同值的数目为 nums[i..j] 的不同计数。

请你返回 nums 中所有子数组的 不同计数 的 平方 和。

子数组指的是一个数组里面一段连续 非空 的元素序列。

示例 1:

输入:nums = [1,2,1]
输出:15
解释:六个子数组分别为:
[1]: 1 个互不相同的元素。
[2]: 1 个互不相同的元素。
[1]: 1 个互不相同的元素。
[1,2]: 2 个互不相同的元素。
[2,1]: 2 个互不相同的元素。
[1,2,1]: 2 个互不相同的元素。
所有不同计数的平方和为 1^2 + 1^2 + 1^2 + 2^2 + 2^2 + 2^2 = 15 。

示例 2:

输入:nums = [2,2]
输出:3
解释:三个子数组分别为:
[2]: 1 个互不相同的元素。
[2]: 1 个互不相同的元素。
[2,2]: 1 个互不相同的元素。
所有不同计数的平方和为 1^2 + 1^2 + 1^2 = 3 。

说明:

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

思路

定义子数组中不同元素值的个数为子数组计数,返回数组所有子数组计数的平方和。

直接的想法是枚举所有子数组,然后将子数组中的元素放入哈希表,累加子数组计数的平方,时间复杂度为 O(n^2)。

代码


/**
 * @date 2026-10-15 9:01
 */
public class SumCounts2913 {

    public int sumCounts_v2(List<Integer> nums) {
        int n = nums.size();
        int res = 0;
        for (int i = 0; i < n; i++) {
            Set<Integer> set = new HashSet<>();
            for (int j = i; j < n; j++) {
                set.add(nums.get(j));
                res += set.size() * set.size();
            }
        }
        return res;
    }

}

性能

3727.最大交替平方和

目标

给你一个整数数组 nums。你可以以任意顺序 重新排列元素 。

数组 arr 的 交替得分 定义为:

  • score = arr[0]^2 - arr[1]^2 + arr[2]^2 - arr[3]^2 + ...

在对 nums 重新排列后,返回其 最大可能的交替得分。

示例 1:

输入: nums = [1,2,3]
输出: 12
解释:
nums 的一种可行重排为 [2,1,3],该排列在所有可能重排中给出了最大交替得分。
交替得分计算如下:
score = 22 - 12 + 32 = 4 - 1 + 9 = 12

示例 2:

输入: nums = [1,-1,2,-2,3,-3]
输出: 16
解释:
nums 的一种可行重排为 [-3,-1,-2,1,3,2],该排列在所有可能重排中给出了最大交替得分。
交替得分计算如下:
score = (-3)^2 - (-1)^2 + (-2)^2 - (1)^2 + (3)^2 - (2)^2 = 9 - 1 + 4 - 1 + 9 - 4 = 16

说明:

  • 1 <= nums.length <= 10^5
  • -4 10^4 <= nums[i] <= 4 10^4

思路

有一个下标从 0 开始的整数数组 nums,数组的交替得分定义为 (nums[0]^2 - nums[1]^2) + (nums[2]^2 - nums[3]^2) + …… ,允许对数组重新排序,返回最大可能的交替得分。

依题意,得分为偶数下标元素的平方减去奇数下标元素的平方,要使得分最大,只需奇数下标的平方值最小。将数组替换为元素的平方,然后排序数组,将前 n/2 个元素放在奇数下标即可。

代码


/**
 * @date 2026-10-13 10:20
 */
public class MaxAlternatingSum3727 {

    public long maxAlternatingSum(int[] nums) {
        long res = 0L;
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            nums[i] = nums[i] * nums[i];
        }
        Arrays.sort(nums);
        for (int i = 0; i < n; i++) {
            if (i < n / 2) {
                res -= nums[i];
            } else {
                res += nums[i];
            }
        }
        return res;
    }
}

性能

2778.特殊元素平方和

目标

给你一个下标从 1 开始、长度为 n 的整数数组 nums 。

对 nums 中的元素 nums[i] 而言,如果 n 能够被 i 整除,即 n % i == 0 ,则认为 nums[i] 是一个 特殊元素 。

返回 nums 中所有 特殊元素 的 平方和 。

示例 1:

输入:nums = [1,2,3,4]
输出:21
解释:nums 中共有 3 个特殊元素:nums[1],因为 4 被 1 整除;nums[2],因为 4 被 2 整除;以及 nums[4],因为 4 被 4 整除。 
因此,nums 中所有特殊元素的平方和等于 nums[1] * nums[1] + nums[2] * nums[2] + nums[4] * nums[4] = 1 * 1 + 2 * 2 + 4 * 4 = 21 。

示例 2:

输入:nums = [2,7,1,19,18,3]
输出:63
解释:nums 中共有 4 个特殊元素:nums[1],因为 6 被 1 整除;nums[2] ,因为 6 被 2 整除;nums[3],因为 6 被 3 整除;以及 nums[6],因为 6 被 6 整除。 
因此,nums 中所有特殊元素的平方和等于 nums[1] * nums[1] + nums[2] * nums[2] + nums[3] * nums[3] + nums[6] * nums[6] = 2 * 2 + 7 * 7 + 1 * 1 + 3 * 3 = 63 。 

说明:

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

思路

有一个下标从 1 开始的数组 nums,如果 n % i == 0 则称 nums[i] 为特殊元素,返回特殊元素的平方和。

根据题意模拟即可。

代码


/**
 * @date 2026-10-12 9:38
 */
public class SumOfSquares2778 {

    public int sumOfSquares(int[] nums) {
        int n = nums.length;
        int res = 0;
        for (int i = 0; i < n; i++) {
            if (n % (i + 1) == 0) {
                res += nums[i] * nums[i];
            }
        }
        return res;
    }
}

性能

3550.数位和等于下标的最小下标

目标

给你一个整数数组 nums 。

返回满足 nums[i] 的数位和(每一位数字相加求和)等于 i 的 最小 下标 i 。

如果不存在满足要求的下标,返回 -1 。

示例 1:

输入:nums = [1,3,2]
输出:2
解释:
nums[2] = 2,其数位和等于 2 ,与其下标 i = 2 相等。因此,输出为 2 。

示例 2:

输入:nums = [1,10,11]
输出:1
解释:
nums[1] = 10,其数位和等于 1 + 0 = 1,与其下标 i = 1 相等。
nums[2] = 11,其数位和等于是 1 + 1 = 2,与其下标 i = 2 相等。
由于下标 1 是满足要求的最小下标,输出为 1 。

示例 3:

输入:nums = [1,2,3]
输出:-1
解释:
由于不存在满足要求的下标,输出为 -1 。

说明:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 1000

思路

已知数组 nums,返回数位和等于数组下标的最小下标,如果不存在返回 -1。

依题意模拟即可。

代码


/**
 * @date 2026-09-24 8:43
 */
public class SmallestIndex3550 {

    public int smallestIndex(int[] nums) {
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            int num = nums[i], sum = 0;
            while (num > 0) {
                sum += num % 10;
                num /= 10;
            }
            if (sum == i) {
                return i;
            }
        }
        return -1;
    }
}

性能

3525_求出数组的X值II

目标

给你一个由 正整数 组成的数组 nums 和一个 正整数 k。同时给你一个二维数组 queries,其中 queries[i] = [indexi, valuei, starti, xi]。

你可以对 nums 执行 一次 操作,移除 nums 的任意 后缀 ,使得 nums 仍然非空。

给定一个 x,nums 的 x值 定义为执行以上操作后剩余元素的 乘积 除以 k 的 余数 为 x 的方案数。

对于 queries 中的每个查询,你需要执行以下操作,然后确定 xi 对应的 nums 的 x值:

  • 将 nums[indexi] 更新为 valuei。仅这个更改在接下来的所有查询中保留。
  • 移除 前缀 nums[0..(starti - 1)](nums[0..(-1)] 表示 空前缀 )。

返回一个长度为 queries.length 的数组 result,其中 result[i] 是第 i 个查询的答案。

数组的一个 前缀 是从数组开始位置到任意位置的子数组。

数组的一个 后缀 是从数组中任意位置开始直到结束的子数组。

子数组 是数组中一段连续的元素序列。

注意:操作中所选的前缀或后缀可以是 空的 。

注意:x值在本题中与问题 I 有不同的定义。

示例 1:

输入: nums = [1,2,3,4,5], k = 3, queries = [[2,2,0,2],[3,3,3,0],[0,1,0,1]]
输出: [2,2,2]
解释:
对于查询 0,nums 变为 [1, 2, 2, 4, 5] 。移除空前缀后,可选操作包括:
移除后缀 [2, 4, 5] ,nums 变为 [1, 2]。
不移除任何后缀。nums 保持为 [1, 2, 2, 4, 5],乘积为 80,对 3 取余为 2。
对于查询 1,nums 变为 [1, 2, 2, 3, 5] 。移除前缀 [1, 2, 2] 后,可选操作包括:
不移除任何后缀,nums 为 [3, 5]。
移除后缀 [5] ,nums 为 [3]。
对于查询 2,nums 保持为 [1, 2, 2, 3, 5] 。移除空前缀后。可选操作包括:
移除后缀 [2, 2, 3, 5]。nums 为 [1]。
移除后缀 [3, 5]。nums 为 [1, 2, 2]。

示例 2:

输入: nums = [1,2,4,8,16,32], k = 4, queries = [[0,2,0,2],[0,2,0,1]]
输出: [1,0]
解释:
对于查询 0,nums 变为 [2, 2, 4, 8, 16, 32]。唯一可行的操作是:
移除后缀 [2, 4, 8, 16, 32]。
对于查询 1,nums 仍为 [2, 2, 4, 8, 16, 32]。没有任何操作能使余数为 1。

示例 3:

输入: nums = [1,1,2,1,1], k = 2, queries = [[2,1,0,1]]
输出: [5]

说明:

  • 1 <= nums[i] <= 10^9
  • 1 <= nums.length <= 10^5
  • 1 <= k <= 5
  • 1 <= queries.length <= 2 * 10^4
  • queries[i] == [indexi, valuei, starti, xi]
  • 0 <= indexi <= nums.length - 1
  • 1 <= valuei <= 10^9
  • 0 <= starti <= nums.length - 1
  • 0 <= xi <= k - 1

思路

代码

性能

3414.不重叠区间的最大得分

目标

给你一个二维整数数组 intervals,其中 intervals[i] = [li, ri, weighti]。区间 i 的起点为 li,终点为 ri,权重为 weighti。你最多可以选择 4 个互不重叠 的区间。所选择区间的 得分 定义为这些区间权重的总和。

返回一个至多包含 4 个下标且 字典序最小 的数组,表示从 intervals 中选中的互不重叠且得分最大的区间。

如果两个区间没有任何重叠点,则称二者 互不重叠 。特别地,如果两个区间共享左边界或右边界,也认为二者重叠。

示例 1:

输入: intervals = [[1,3,2],[4,5,2],[1,5,5],[6,9,3],[6,7,1],[8,9,1]]
输出: [2,3]
解释:
可以选择下标为 2 和 3 的区间,其权重分别为 5 和 3。

示例 2:

输入: intervals = [[5,8,1],[6,7,7],[4,7,3],[9,10,6],[7,8,2],[11,14,3],[3,5,5]]
输出: [1,3,5,6]
解释:
可以选择下标为 1、3、5 和 6 的区间,其权重分别为 7、6、3 和 5。

说明:

  • 1 <= intervals.length <= 5 * 10^4
  • intervals[i].length == 3
  • intervals[i] = [li, ri, weighti]
  • 1 <= li <= ri <= 10^9
  • 1 <= weighti <= 10^9

思路

// todo

代码

性能

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

性能