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

}

性能

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

性能

1614.括号的最大嵌套深度

目标

给定 有效括号字符串 s,返回 s 的 嵌套深度。嵌套深度是嵌套括号的 最大 数量。

示例 1:

输入:s = "(1+(2*3)+((8)/4))+1"
输出:3
解释:数字 8 在嵌套的 3 层括号中。

示例 2:

输入:s = "(1)+((2))+(((3)))"
输出:3
解释:数字 3 在嵌套的 3 层括号中。

示例 3:

输入:s = "()(())((()()))"
输出:3

说明:

  • 1 <= s.length <= 100
  • s 由数字 0-9 和字符 '+'、'-'、'*'、'/'、'('、')' 组成
  • 题目数据保证括号字符串 s 是 有效的括号字符串

思路

s 是一个有效的括号字符串,其中的括号是能够合法匹配的。返回 s 中括号嵌套的最大深度。

遇到 ( 深度加一,遇到 ) 深度减一,记录深度的最大值即可。

代码


/**
 * @date 2026-09-28 10:04
 */
public class MaxDepth1614 {

    public int maxDepth(String s) {
        int res = 0;
        int n = s.length();
        int depth = 0;
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == '(') {
                depth++;
                res = Math.max(res, depth);
            } else if (s.charAt(i) == ')') {
                depth--;
            }
        }
        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;
    }
}

性能

3498.字符串的反转度

目标

给你一个字符串 s,计算其 反转度。

反转度的计算方法如下:

  1. 对于每个字符,将其在 反转 字母表中的位置('a' = 26, 'b' = 25, ..., 'z' = 1)与其在字符串中的位置(下标从1 开始)相乘。
  2. 将这些乘积加起来,得到字符串中所有字符的和。

返回 反转度。

示例 1:

输入: s = "abc"
输出: 148
解释:
字母 反转字母表中的位置 字符串中的位置 乘积
'a'        26              1        26
'b'        25              2        50
'c'        24              3        72
反转度是 26 + 50 + 72 = 148 。

示例 2:

输入: s = "zaza"
输出: 160
解释:
字母 反转字母表中的位置 字符串中的位置 乘积
'z'        1             1         1
'a'        26            2        52
'z'        1             3         3
'a'        26            4        104
反转度是 1 + 52 + 3 + 104 = 160 。

说明:

  • 1 <= s.length <= 1000
  • s 仅包含小写字母。

思路

定义字符串中字符的反转度为每个字符的下标(从 1 开始)乘以该字符在反转字符表中的位置的乘积,字符串的反转度是其字符反转度之和。

依题意模拟即可。

代码


/**
 * @date 2026-09-21 16:49
 */
public class ReverseDegree3498 {

    public int reverseDegree(String s) {
        int res = 0;
        int n = s.length();
        for (int i = 1; i <= n; i++) {
            res += ('z' - s.charAt(i - 1) + 1) * i;
        }
        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,构造数组 prefixGcd,prefixGcd[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);
    }

}

性能

2685.统计完全连通分量的数量

目标

给你一个整数 n 。现有一个包含 n 个顶点的 无向 图,顶点按从 0 到 n - 1 编号。给你一个二维整数数组 edges 其中 edges[i] = [ai, bi] 表示顶点 ai 和 bi 之间存在一条 无向 边。

返回图中 完全连通分量 的数量。

如果在子图中任意两个顶点之间都存在路径,并且子图中没有任何一个顶点与子图外部的顶点共享边,则称其为 连通分量 。

如果连通分量中每对节点之间都存在一条边,则称其为 完全连通分量 。

示例 1:

输入:n = 6, edges = [[0,1],[0,2],[1,2],[3,4]]
输出:3
解释:如上图所示,可以看到此图所有分量都是完全连通分量。

示例 2:

输入:n = 6, edges = [[0,1],[0,2],[1,2],[3,4],[3,5]]
输出:1
解释:包含节点 0、1 和 2 的分量是完全连通分量,因为每对节点之间都存在一条边。
包含节点 3 、4 和 5 的分量不是完全连通分量,因为节点 4 和 5 之间不存在边。
因此,在图中完全连接分量的数量是 1 。

说明:

  • 1 <= n <= 50
  • 0 <= edges.length <= n * (n - 1) / 2
  • edges[i].length == 2
  • 0 <= ai, bi <= n - 1
  • ai != bi
  • 不存在重复的边

思路

求无向图中完全连通分量的个数。完全连通分量指连通分量中任意两个节点之间都有一条边。

暴力解法是使用并查集维护连通分量,找出同一连通分量内的节点,判断两两之间是否有边。

优化点:可以利用节点与边的关系来判断是否是完全连通分量,节点 v 与 边 e 的关系为:e = C(v, 2) = v * (v - 1) / 2。

代码


/**
 * @date 2026-07-14 11:27
 */
public class CountCompleteComponents2685 {

    private class UnionFind {

        private final int[] fa;

        public UnionFind(int n) {
            fa = new int[n];
            Arrays.setAll(fa, i -> i);
        }

        public int find(int e) {
            if (e != fa[e]) {
                fa[e] = find(fa[e]);
            }
            return fa[e];
        }

        public void union(int a, int b) {
            int x = find(a);
            int y = find(b);
            if (x > y) {
                fa[x] = y;
            } else {
                fa[y] = x;
            }
        }

        public int getCompleteComponents(Set<Integer>[] g) {
            int n = fa.length;
            int res = 0;
            Set<Integer> visited = new HashSet<>();
            for (int i = 0; i < n; i++) {
                if (visited.contains(i)) {
                    continue;
                }
                visited.add(i);
                List<Integer> list = new ArrayList<>();
                for (int j = 0; j < n; j++) {
                    if (find(j) == find(i)) {
                        visited.add(j);
                        list.add(j);
                    }
                }
                int size = list.size();
                boolean flag = true;
                here:
                for (int p = 0; p < size; p++) {
                    for (int q = p + 1; q < size; q++) {
                        if (!g[list.get(p)].contains(list.get(q))) {
                            flag = false;
                            break here;
                        }
                    }
                }
                if (flag) {
                    res++;
                }
            }
            return res;
        }
    }

    public int countCompleteComponents(int n, int[][] edges) {
        UnionFind uf = new UnionFind(n);
        Set<Integer>[] g = new HashSet[n];
        Arrays.setAll(g, x -> new HashSet<>());
        for (int[] edge : edges) {
            int a = edge[0];
            int b = edge[1];
            uf.union(a, b);
            g[a].add(b);
            g[b].add(a);
        }
        return uf.getCompleteComponents(g);
    }

}

性能

3754.连接非零数字并乘以其数字和I

目标

给你一个整数 n。

将 n 中所有的 非零数字 按照它们的原始顺序连接起来,形成一个新的整数 x。如果不存在 非零数字 ,则 x = 0。

sum 为 x 中所有数字的 数字和 。

返回一个整数,表示 x * sum 的值。

示例 1:

输入: n = 10203004
输出: 12340
解释:
非零数字是 1、2、3 和 4。因此,x = 1234。
数字和为 sum = 1 + 2 + 3 + 4 = 10。
因此,答案是 x * sum = 1234 * 10 = 12340。

示例 2:

输入: n = 1000
输出: 1
解释:
非零数字是 1,因此 x = 1 且 sum = 1。
因此,答案是 x * sum = 1 * 1 = 1。

说明:

  • 0 <= n <= 10^9

思路

计算整数 n 的所有非零数字之和记为 sum,去掉 n 中的 0 形成的新整数记为 x,返回 x * sum 的值。

依题意模拟即可。

代码


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

    public long sumAndMultiply(int n) {
        long sum = 0;
        long x = 0;
        int base = 1;
        while (n > 0) {
            int rem = n % 10;
            sum += rem;
            x += rem * base;
            base *= rem == 0 ? 1 : 10;
            n /= 10;
        }
        return x * sum;
    }
}

性能