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

}

性能

3723.数位平方和的最大值

目标

给你两个 正 整数 num 和 sum。

如果一个正整数 n 满足以下两个条件,则称其为 好整数 :

  • n 的位数 恰好 为 num。
  • n 的各位数字之和 恰好 为 sum。

一个 好整数 n 的 分数 定义为 n 的各位数字的平方和。

返回一个 字符串 ,表示能获得 最大分数 的 好整数 n。如果有多个可能的整数,返回 最大 的那个。如果不存在这样的整数,返回一个空字符串。

示例 1:

输入: num = 2, sum = 3
输出: "30"
解释:
有 3 个好整数:12、21 和 30。
12 的分数是 12 + 22 = 5。
21 的分数是 22 + 12 = 5。
30 的分数是 32 + 02 = 9。
最大分数是 9,由好整数 30 获得。因此,答案是 "30"。

示例 2:

输入: num = 2, sum = 17
输出: "98"
解释:
有两个好整数:89 和 98。
89 的分数是 82 + 92 = 145。
98 的分数是 92 + 82 = 145。
最大分数是 145。获得此分数的最大好整数是 98。因此,答案是 "98"。

示例 3:

输入: num = 1, sum = 10
输出: ""
解释:
不存在恰好有 1 位数字且各位数字之和为 10 的整数。因此,答案是 ""。

说明:

  • 1 <= num <= 2 * 10^5
  • 1 <= sum <= 2 * 10^6

思路

定义数位长度为 num,数位之和为 sum 的整数为好整数,好整数的分数定义为各位数字的平方和,返回分数最大的好整数,如果分数相同则返回整数值最大的,如果不存在返回空串。

贪心策略就是取当前位所能取的最大值,余下的补 0。

代码


/**
 * @date 2026-10-14 9:21
 */
public class MaxSumOfSquares3723 {

    public String maxSumOfSquares(int num, int sum) {
        StringBuilder sb = new StringBuilder();
        while (num > 0) {
            int d = Math.min(sum, 9);
            sum -= d;
            num--;
            sb.append(d);
        }
        return sum == 0 ? sb.toString() : "";
    }

}

性能

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

性能

1541.平衡括号字符串的最少插入次数

目标

给你一个括号字符串 s ,它只包含字符 '(' 和 ')' 。一个括号字符串被称为平衡的当它满足:

  • 任何左括号 '(' 必须对应两个连续的右括号 '))' 。
  • 左括号 '(' 必须在对应的连续两个右括号 '))' 之前。

比方说 "())", "())(())))" 和 "(())())))" 都是平衡的, ")()", "()))" 和 "(()))" 都是不平衡的。

你可以在任意位置插入字符 '(' 和 ')' 使字符串平衡。

请你返回让 s 平衡的最少插入次数。

示例 1:

输入:s = "(()))"
输出:1
解释:第二个左括号有与之匹配的两个右括号,但是第一个左括号只有一个右括号。我们需要在字符串结尾额外增加一个 ')' 使字符串变成平衡字符串 "(())))" 。

示例 2:

输入:s = "())"
输出:0
解释:字符串已经平衡了。

示例 3:

输入:s = "))())("
输出:3
解释:添加 '(' 去匹配最开头的 '))' ,然后添加 '))' 去匹配最后一个 '(' 。

示例 4:

输入:s = "(((((("
输出:12
解释:添加 12 个 ')' 得到平衡字符串。

示例 5:

输入:s = ")))))))"
输出:5
解释:在字符串开头添加 4 个 '(' 并在结尾添加 1 个 ')' ,字符串变成平衡字符串 "(((())))))))" 。

说明:

  • 1 <= s.length <= 10^5
  • s 只包含 '(' 和 ')' 。

思路

定义平衡括号字符串是每一个左括号都对应有两个连续右括号的字符串。有一个括号字符串 s,每次操作可以插入一个 ( 或者 ),求使括号字符串变平衡的最小操作次数。

记录未匹配的左括号数量 lc,遇到连续的右括号直接滑倒结束并计数 rc,贪心策略:

  • 如果 lc >= rc,如果 rc 为奇数,需要补一个右括号,操作加一,lc 减去已匹配的数量,rc 置零。
  • 否则,每两个右括号匹配需要补一个左括号,操作加 rc / 2,如果 rc 是奇数,需要补一对括号,操作加 2。

代码


/**
 * @date 2026-10-09 9:09
 */
public class MinInsertions1541 {

    public int minInsertions(String s) {
        char[] chars = s.toCharArray();
        int n = s.length();
        int lc = 0, rc = 0, res = 0;
        int i = 0;
        while (i < n) {
            if (chars[i] == '(') {
                lc += 2;
                i++;
            } else {
                while (i < n && chars[i] == ')') {
                    i++;
                    rc++;
                }
            }
            if (lc >= rc) {
                res += rc % 2;
                lc -= rc + rc % 2;
                rc = 0;
            } else {
                rc -= lc;
                int rem = rc % 2;
                res += rc / 2 + (rem == 0 ? 0 : 2);
                rc = 0;
                lc = 0;
            }
        }
        return res + lc;
    }

}

性能

1021.删除最外层的括号

目标

有效括号字符串为空 ""、"(" + A + ")" 或 A + B ,其中 A 和 B 都是有效的括号字符串,+ 代表字符串的连接。

  • 例如,"","()","(())()" 和 "(()(()))" 都是有效的括号字符串。

如果有效字符串 s 非空,且不存在将其拆分为 s = A + B 的方法,我们称其为原语(primitive),其中 A 和 B 都是非空有效括号字符串。

给出一个非空有效字符串 s,考虑将其进行原语化分解,使得:s = P_1 + P_2 + ... + P_k,其中 P_i 是有效括号字符串原语。

对 s 进行原语化分解,删除分解中每个原语字符串的最外层括号,返回 s 。

示例 1:

输入:s = "(()())(())"
输出:"()()()"
解释:
输入字符串为 "(()())(())",原语化分解得到 "(()())" + "(())",
删除每个部分中的最外层括号后得到 "()()" + "()" = "()()()"。

示例 2:

输入:s = "(()())(())(()(()))"
输出:"()()()()(())"
解释:
输入字符串为 "(()())(())(()(()))",原语化分解得到 "(()())" + "(())" + "(()(()))",
删除每个部分中的最外层括号后得到 "()()" + "()" + "()(())" = "()()()()(())"。

示例 3:

输入:s = "()()"
输出:""
解释:
输入字符串为 "()()",原语化分解得到 "()" + "()",
删除每个部分中的最外层括号后得到 "" + "" = ""。

说明:

  • 1 <= s.length <= 10^5
  • s[i] 为 '(' 或 ')'
  • s 是一个有效括号字符串

思路

有一个仅由 ( 或 ) 组成非空有效括号字符串。删掉最外层的括号并返回删除后的字符串。最外层指没有被嵌套在其它括号内部的括号。

如果左括号的数量等于右括号的数量说明匹配到了最外层括号,去掉首尾保留中间即可。

代码


/**
 * @date 2026-10-08 9:12
 */
public class RemoveOuterParentheses1021 {

    public String removeOuterParentheses(String s) {
        StringBuilder sb = new StringBuilder();
        int n = s.length();
        int lc = 0, rc = 0, l = 0;
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == '(') {
                lc++;
                if (lc == 1) {
                    l = i;
                }
            } else {
                rc++;
                if (lc == rc) {
                    sb.append(s.substring(l + 1, i));
                    lc = 0;
                    rc = 0;
                }
            }
        }
        return sb.toString();
    }
}

性能

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

性能

1658.将x减到0的最小操作数

目标

给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。

如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1 。

示例 1:

输入:nums = [1,1,4,2,3], x = 5
输出:2
解释:最佳解决方案是移除后两个元素,将 x 减到 0 。

示例 2:

输入:nums = [5,6,7,8,9], x = 4
输出:-1

示例 3:

输入:nums = [3,2,20,1,1,3], x = 10
输出:5
解释:最佳解决方案是移除后三个元素和前两个元素(总共 5 次操作),将 x 减到 0 。

说明:

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

思路

有一个正整数数组 nums,每一次操作可以移除剩余数组的最左或最右元素,求移除元素和等于 x 的最小操作数,如果不存在则返回 -1。

将问题转化为求子数组和为 sum - x 的最大长度,可以使用滑动窗口。

代码


/**
 * @date 2026-09-23 8:49
 */
public class MinOperations1658 {

    public int minOperations(int[] nums, int x) {
        int n = nums.length;
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        if (sum < x) {
            return -1;
        } else if (sum == x) {
            return n;
        }
        int target = sum - x;
        int res = 0;
        int l = 0;
        sum = 0;
        for (int r = 0; r < n; r++) {
            sum += nums[r];
            while (sum > target) {
                sum -= nums[l++];
            }
            if (sum == target) {
                res = Math.max(res, r - l + 1);
            }
        }
        return res == 0 ? -1 : n - res;
    }

}

性能

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

思路

代码

性能