3963.构造恰好一条路径的网格

目标

给你两个整数 m 和 n,分别表示网格的行数和列数。

请你构造 任意 一个只包含字符 '.' 和 '#' 的 m x n 网格,其中:

  • '.' 表示空单元格。
  • '#' 表示障碍物单元格。

有效路径 是满足以下条件的空单元格序列:

  • 从左上角单元格 (0, 0) 开始。
  • 在右下角单元格 (m - 1, n - 1) 结束。
  • 只能向:
    • 右移动,从 (i, j) 到 (i, j + 1),或者
    • 下移动,从 (i, j) 到 (i + 1, j)。

返回任意一个从左上角到右下角 恰好只有一条有效路径 的网格。

示例 1:

输入: m = 2, n = 3
输出: ["..#","#.."]
解释:
唯一的有效路径是:(0,0) → (0,1) → (1,1) → (1,2)

示例 2:

输入: m = 3, n = 3
输出: ["..#","#..","##."]
解释:
唯一的有效路径是:(0,0) → (0,1) → (1,1) → (1,2) → (2,2)

示例 3:

输入: m = 1, n = 4
输出: ["...."]
解释:
唯一的有效路径是:(0,0) → (0,1) → (0,2) → (0,3)

说明:

1 <= m, n <= 25

思路

构造一个 m x n 矩阵,要求从左上到右下 仅有一条 有效路径,使用 . 表示空格,# 表示有障碍物,返回任意一种构造即可。

直接的想法是第一行全空格,下面的行除了最后一列全是障碍物。

代码


/**
 * @date 2026-10-27 8:49
 */
public class CreateGrid3963 {

    public String[] createGrid_v1(int m, int n) {
        String[] res = new String[m];
        char[] chars = new char[n];
        Arrays.fill(chars, '#');
        chars[n - 1] = '.';
        String row = new String(chars);
        Arrays.fill(res, row);
        chars = new char[n];
        Arrays.fill(chars, '.');
        res[0] = new String(chars);
        return 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;
    }

}

性能

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

性能

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

性能

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

性能

836.矩形重叠

目标

矩形以列表 [x1, y1, x2, y2] 的形式表示,其中 (x1, y1) 为左下角的坐标,(x2, y2) 是右上角的坐标。矩形的上下边平行于 x 轴,左右边平行于 y 轴。

如果相交的面积为 正 ,则称两矩形重叠。需要明确的是,只在角或边接触的两个矩形不构成重叠。

给出两个矩形 rec1 和 rec2 。如果它们重叠,返回 true;否则,返回 false 。

示例 1:

输入:rec1 = [0,0,2,2], rec2 = [1,1,3,3]
输出:true

示例 2:

输入:rec1 = [0,0,1,1], rec2 = [1,0,2,1]
输出:false

示例 3:

输入:rec1 = [0,0,1,1], rec2 = [2,2,3,3]
输出:false

说明:

  • rect1.length == 4
  • rect2.length == 4
  • -10^9 <= rec1[i], rec2[i] <= 10^9
  • rec1 和 rec2 表示一个面积不为零的有效矩形

思路

使用数组 [x1, y1, x2, y2] 表示一个矩形的 左下 (x1, y1) 与 右上 (x2, y2) 顶点。给出两个数组 rec1 与 rec2,判断它们是否重叠。

如果两个矩形重叠,那么两个矩形在两个坐标轴方向的投影区间都应该相交。

代码


/**
 * @date 2026-09-14 9:08
 */
public class IsRectangleOverlap836 {

    public boolean isRectangleOverlap(int[] rec1, int[] rec2) {
        int x1 = rec1[0], x3 = rec2[0];
        int y1 = rec1[1], y3 = rec2[1];
        int x2 = rec1[2], x4 = rec2[2];
        int y2 = rec1[3], y4 = rec2[3];
        return !(x2 <= x3 || x4 <= x1) && !(y2 <= y3 || y4 <= y1);
    }

}

性能

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

}

性能