3033.修改矩阵

目标

给你一个下标从 0 开始、大小为 m x n 的整数矩阵 matrix ,新建一个下标从 0 开始、名为 answer 的矩阵。使 answer 与 matrix 相等,接着将其中每个值为 -1 的元素替换为所在列的 最大 元素。

返回矩阵 answer 。

示例 1:

输入:matrix = [[1,2,-1],[4,-1,6],[7,8,9]]
输出:[[1,2,9],[4,8,6],[7,8,9]]
解释:上图显示了发生替换的元素(蓝色区域)。
- 将单元格 [1][1] 中的值替换为列 1 中的最大值 8 。
- 将单元格 [0][2] 中的值替换为列 2 中的最大值 9 。

示例 2:

输入:matrix = [[3,-1],[5,2]]
输出:[[3,2],[5,2]]
解释:上图显示了发生替换的元素(蓝色区域)。

说明:

  • m == matrix.length
  • n == matrix[i].length
  • 2 <= m, n <= 50
  • -1 <= matrix[i][j] <= 100
  • 测试用例中生成的输入满足每列至少包含一个非负整数。

思路

使用矩阵各列的最大值替换该列中值为-1的元素。

先求出各列的最大值,然后替换。

代码

/**
 * @date 2024-07-05 0:26
 */
public class ModifiedMatrix3033 {

    /**
     * 优化到一个循环中,使用局部遍历保存当前列的最大值,
     * 没必要使用数组保存所有列的最大值然后再处理
     */
    public int[][] modifiedMatrix_v1(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        for (int i = 0; i < n; i++) {
            int max = 0;
            for (int j = 0; j < m; j++) {
                max = Math.max(max, matrix[j][i]);
            }
            for (int j = 0; j < m; j++) {
                if (matrix[j][i] == -1) {
                    matrix[j][i] = max;
                }
            }
        }
        return matrix;
    }

    public int[][] modifiedMatrix(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        int[] max = new int[n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                max[i] = Math.max(max[i], matrix[j][i]);
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (matrix[j][i] == -1) {
                    matrix[j][i] = max[i];
                }
            }
        }
        return matrix;
    }
}

性能

3099.哈沙德数

目标

如果一个整数能够被其各个数位上的数字之和整除,则称之为 哈沙德数(Harshad number)。给你一个整数 x 。如果 x 是 哈沙德数 ,则返回 x 各个数位上的数字之和,否则,返回 -1 。

示例 1:

输入: x = 18
输出: 9
解释: x 各个数位上的数字之和为 9 。18 能被 9 整除。因此 18 是哈沙德数,答案是 9 。

示例 2:

输入: x = 23
输出: -1
解释: x 各个数位上的数字之和为 5 。23 不能被 5 整除。因此 23 不是哈沙德数,答案是 -1 。

说明:

  • 1 <= x <= 100

思路

判断给定的整数x的各位数字之和能否整除x,如果可以返回各位数字之和,否则返回-1。

代码

/**
 * @date 2024-07-03 0:40
 */
public class SumOfTheDigitsOfHarshadNumber3099 {

    public int sumOfTheDigitsOfHarshadNumber(int x) {
        int sum = 0;
        // 容易出错的点是直接对x进行修改,后面求余的时候就错了
        int digit = x;
        while (digit > 0) {
            sum += digit % 10;
            digit /= 10;
        }
        return x % sum == 0 ? sum : -1;
    }
}

性能

2710.移除字符串中的尾随零

目标

给你一个用字符串表示的正整数 num ,请你以字符串形式返回不含尾随零的整数 num 。

示例 1:

输入:num = "51230100"
输出:"512301"
解释:整数 "51230100" 有 2 个尾随零,移除并返回整数 "512301" 。

示例 2:

输入:num = "123"
输出:"123"
解释:整数 "123" 不含尾随零,返回整数 "123" 。

说明:

  • 1 <= num.length <= 1000
  • num 仅由数字 0 到 9 组成
  • num 不含前导零

思路

去掉字符串末尾的0。

代码

/**
 * @date 2024-06-29 21:45
 */
public class RemoveTrailingZeros2710 {

    public String removeTrailingZeros(String num) {
        int n = num.length() - 1;
        while (n >= 0 && num.charAt(n) == '0') {
            n--;
        }
        return num.substring(0, n + 1);
    }
}

性能

LCP61.气温变化趋势

目标

力扣城计划在两地设立「力扣嘉年华」的分会场,气象小组正在分析两地区的气温变化趋势,对于第 i ~ (i+1) 天的气温变化趋势,将根据以下规则判断:

  • 若第 i+1 天的气温 高于 第 i 天,为 上升 趋势
  • 若第 i+1 天的气温 等于 第 i 天,为 平稳 趋势
  • 若第 i+1 天的气温 低于 第 i 天,为 下降 趋势

已知 temperatureA[i] 和 temperatureB[i] 分别表示第 i 天两地区的气温。 组委会希望找到一段天数尽可能多,且两地气温变化趋势相同的时间举办嘉年华活动。请分析并返回两地气温变化趋势相同的最大连续天数。

即最大的 n,使得第 i~i+n 天之间,两地气温变化趋势相同

示例 1:

输入: temperatureA = [21,18,18,18,31] temperatureB = [34,32,16,16,17]
输出:2
解释:如下表所示, 第 2~4 天两地气温变化趋势相同,且持续时间最长,因此返回 4 - 2 = 2
天数 0~1 1~2 2~3 3~4
变化趋势A 下降 平稳 平稳 上升
变化趋势B 下降 下降 平稳 上升

示例 2:

输入: temperatureA = [5,10,16,-6,15,11,3] temperatureB = [16,22,23,23,25,3,-16]
输出:3

说明:

  • 2 <= temperatureA.length == temperatureB.length <= 1000
  • -20 <= temperatureA[i], temperatureB[i] <= 40

思路

简单的计数,容易出错的点是忘记比较最后的cnt。

知识点:

  • 如何比较变化是否相同,使用API Integer.compare 或者 计算 (x > y) - (x < y), boolean 值可以隐式转换成 0 或者 1。最直接的就是判断(a>b && c>d) || (a==b && c==d) || (a<b && c<d)

代码

/**
 * @date 2024-06-21 0:35
 */
public class TemperatureTrendLCP61 {

    public int temperatureTrend_v1(int[] temperatureA, int[] temperatureB) {
        int n = temperatureA.length;
        int res = 0;
        int cnt = 0;
        for (int i = 1; i < n; i++) {
            if (Integer.compare(temperatureA[i], temperatureA[i - 1]) == Integer.compare(temperatureB[i], temperatureB[i - 1])) {
                cnt++;
            } else {
                res = Math.max(res, cnt);
                cnt = 0;
            }
        }
        return Math.max(res, cnt);
    }

}

性能

2748.美丽下标对的数目

目标

给你一个下标从 0 开始的整数数组 nums 。如果下标对 i、j 满足 0 ≤ i < j < nums.length ,如果 nums[i] 的 第一个数字 和 nums[j] 的 最后一个数字 互质 ,则认为 nums[i] 和 nums[j] 是一组 美丽下标对 。

返回 nums 中 美丽下标对 的总数目。

对于两个整数 x 和 y ,如果不存在大于 1 的整数可以整除它们,则认为 x 和 y 互质 。换而言之,如果 gcd(x, y) == 1 ,则认为 x 和 y 互质,其中 gcd(x, y) 是 x 和 y 的 最大公因数 。

示例 1:

输入:nums = [2,5,1,4]
输出:5
解释:nums 中共有 5 组美丽下标对:
i = 0 和 j = 1 :nums[0] 的第一个数字是 2 ,nums[1] 的最后一个数字是 5 。2 和 5 互质,因此 gcd(2,5) == 1 。
i = 0 和 j = 2 :nums[0] 的第一个数字是 2 ,nums[2] 的最后一个数字是 1 。2 和 5 互质,因此 gcd(2,1) == 1 。
i = 1 和 j = 2 :nums[1] 的第一个数字是 5 ,nums[2] 的最后一个数字是 1 。2 和 5 互质,因此 gcd(5,1) == 1 。
i = 1 和 j = 3 :nums[1] 的第一个数字是 5 ,nums[3] 的最后一个数字是 4 。2 和 5 互质,因此 gcd(5,4) == 1 。
i = 2 和 j = 3 :nums[2] 的第一个数字是 1 ,nums[3] 的最后一个数字是 4 。2 和 5 互质,因此 gcd(1,4) == 1 。
因此,返回 5 。

示例 2:

输入:nums = [11,21,12]
输出:2
解释:共有 2 组美丽下标对:
i = 0 和 j = 1 :nums[0] 的第一个数字是 1 ,nums[1] 的最后一个数字是 1 。gcd(1,1) == 1 。
i = 0 和 j = 2 :nums[0] 的第一个数字是 1 ,nums[2] 的最后一个数字是 2 。gcd(1,2) == 1 。
因此,返回 2 。

说明:

  • 2 <= nums.length <= 100
  • 1 <= nums[i] <= 9999
  • nums[i] % 10 != 0

思路

有一个整数数组,从中任选两个元素,如果下标小的元素的第一个数字与下标大的元素的最后一个数字互质,则称这两个元素为美丽下标对。求数组中美丽下标对的总数。

知识点:

  • 如何获取元素值的第一个数字,while(num>=10){num /=10;}
  • 如何判断互质,欧几里得算法

代码

/**
 * @date 2024-06-20 8:37
 */
public class CountBeautifulPairs2748 {

    /**
     * 优化,将外层循环获取第一个数字,然后依次向后比较
     * 改为记录之前遍历过数字的第一个数(1~9)的出现次数
     * 循环的时候只需遍历1~9 9个数字,取其中出现次数不为0的与当前数的最后一个数判断是否互质
     * 累加出现次数即可
     */
    public int countBeautifulPairs_v1(int[] nums) {
        int res = 0;
        int[] firstDigitsCnt = new int[10];
        for (int num : nums) {
            for (int j = 1; j < 10; j++) {
                if (firstDigitsCnt[j] != 0 && gcd(j, num % 10) == 1) {
                    res += firstDigitsCnt[j];
                }
            }
            while (num >= 10) {
                num /= 10;
            }
            firstDigitsCnt[num]++;
        }
        return res;
    }

    public int gcd(int x, int y) {
        return y == 0 ? x : gcd(y, x % y);
    }

    public int countBeautifulPairs_v2(int[] nums) {
        int res = 0;
        int[] firstDigitsCnt = new int[10];
        int[][] prime = new int[][]{
                {},
                {1, 2, 3, 4, 5, 6, 7, 8, 9},
                {1, 3, 5, 7, 9},
                {1, 2, 4, 5, 7, 8},
                {1, 3, 5, 7, 9},
                {1, 2, 3, 4, 6, 7, 8, 9},
                {1, 5, 7},
                {1, 2, 3, 4, 5, 6, 8, 9},
                {1, 3, 5, 7, 9},
                {1, 2, 4, 5, 7, 8}
        };
        for (int num : nums) {
            for (int p : prime[num % 10]) {
                res += firstDigitsCnt[p];
            }
            while (num >= 10) {
                num /= 10;
            }
            firstDigitsCnt[num]++;
        }
        return res;
    }
}

性能

最快的算法是预处理1~9对应的互质数组

521.最长特殊序列Ⅰ

目标

给你两个字符串 a 和 b,请返回 这两个字符串中 最长的特殊序列 的长度。如果不存在,则返回 -1 。

「最长特殊序列」 定义如下:该序列为 某字符串独有的最长子序列(即不能是其他字符串的子序列) 。

字符串 s 的子序列是在从 s 中删除任意数量的字符后可以获得的字符串。

  • 例如,"abc" 是 "aebdc" 的子序列,因为删除 "aebdc" 中斜体加粗的字符可以得到 "abc" 。 "aebdc" 的子序列还包括 "aebdc" 、 "aeb" 和 "" (空字符串)。

示例 1:

输入: a = "aba", b = "cdc"
输出: 3
解释: 最长特殊序列可为 "aba" (或 "cdc"),两者均为自身的子序列且不是对方的子序列。

示例 2:

输入:a = "aaa", b = "bbb"
输出:3
解释: 最长特殊序列是 "aaa" 和 "bbb" 。

示例 3:

输入:a = "aaa", b = "aaa"
输出:-1
解释: 字符串 a 的每个子序列也是字符串 b 的每个子序列。同样,字符串 b 的每个子序列也是字符串 a 的子序列。

说明:

  • 1 <= a.length, b.length <= 100
  • a 和 b 由小写英文字母组成

思路

求两个字符串独有子序列的最大长度。很明显,如果二者长度不等则最大独有子序列就是最长字符串长度;如果二者长度相等,则需要看字符串是否相等,如果相等则表明没有独有子序列,返回-1,否则返回字符串长度。

代码

/**
 * @date 2024-06-16 0:07
 */
public class FindLUSlength521 {
    public int findLUSlength(String a, String b) {
        if (a.equals(b)) {
            return -1;
        } else {
            return Math.max(a.length(), b.length());
        }
    }
}

性能

202.快乐数

目标

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入:n = 2
输出:false

提示:

1 <= n <= 2^31 - 1

思路

难点是如何确定停止条件,我甚至想过记录循环次数如果超过某一个数就返回false。我意识到这可能是一个数学问题,就放弃了。

看了题解才明白,问题看似是开放的,但也是有规律的,关键是如何分析这个问题。

考虑最终可能出现的情况:

  • 最终会得到 1。
  • 最终会进入循环。
  • 值会越来越大,最后接近无穷大。

考虑不同位数数字的最大值,进行一次计算的结果:

位数 最大值 下一个值
1 9 81
2 99 162
3 999 243
4 9999 324
13 9999999999999 81*13=1053

相应位上小于最大值的数字,其下一个值也必定小于最大值的下一个值。

意识到存在循环是很重要的,然后我们可以使用哈希表记录出现过的元素,也可以使用弗洛伊德循环检测算法(Floyd's Cycle-Finding Algorithm)又称为龟兔赛跑算法(Tortoise and Hare Algorithm),注意不是图论中求最短路径的弗洛伊德算法。

// todo 自己实现一下

代码

/**
 * @date 2024-06-15 20:59
 */
public class IsHappy202 {

    /**
     * 快慢指针,也是用来检测链表中是否存在环
     * 快慢如果相遇就说明存在环,否则快的先遇到1
     */
    class Solution_v1 {
        public int getNext(int n) {
            int totalSum = 0;
            while (n > 0) {
                int d = n % 10;
                n = n / 10;
                totalSum += d * d;
            }
            return totalSum;
        }

        public boolean isHappy(int n) {
            int slowRunner = n;
            int fastRunner = getNext(n);
            while (fastRunner != 1 && slowRunner != fastRunner) {
                slowRunner = getNext(slowRunner);
                fastRunner = getNext(getNext(fastRunner));
            }
            return fastRunner == 1;
        }
    }

    /**
     * Set记录每次的数字,如果重复就返回false
     */
    class Solution {
        private int getNext(int n) {
            int totalSum = 0;
            while (n > 0) {
                int d = n % 10;
                n = n / 10;
                totalSum += d * d;
            }
            return totalSum;
        }

        public boolean isHappy(int n) {
            Set<Integer> seen = new HashSet<>();
            while (n != 1 && !seen.contains(n)) {
                seen.add(n);
                n = getNext(n);
            }
            return n == 1;
        }
    }

    /**
     * 实际上只会存在一个循环4→16→37→58→89→145→42→20→4
     */
    private static Set<Integer> cycleMembers =
        new HashSet<>(Arrays.asList(4, 16, 37, 58, 89, 145, 42, 20));

    public int getNext(int n) {
        int totalSum = 0;
        while (n > 0) {
            int d = n % 10;
            n = n / 10;
            totalSum += d * d;
        }
        return totalSum;
    }

    public boolean isHappy(int n) {
        while (n != 1 && !cycleMembers.contains(n)) {
            n = getNext(n);
        }
        return n == 1;
    }

}

性能

2806.取整购买后的账户余额

目标

一开始,你的银行账户里有 100 块钱。

给你一个整数purchaseAmount ,它表示你在一次购买中愿意支出的金额。

在一个商店里,你进行一次购买,实际支出的金额会向 最近 的 10 的 倍数 取整。换句话说,你实际会支付一个 非负 金额 roundedAmount ,满足 roundedAmount 是 10 的倍数且 abs(roundedAmount - purchaseAmount) 的值 最小 。

如果存在多于一个最接近的 10 的倍数,较大的倍数 是你的实际支出金额。

请你返回一个整数,表示你在愿意支出金额为 purchaseAmount 块钱的前提下,购买之后剩下的余额。

注意: 0 也是 10 的倍数。

示例 1:

输入:purchaseAmount = 9
输出:90
解释:这个例子中,最接近 9 的 10 的倍数是 10 。所以你的账户余额为 100 - 10 = 90 。

示例 2:

输入:purchaseAmount = 15
输出:80
解释:这个例子中,有 2 个最接近 15 的 10 的倍数:10 和 20,较大的数 20 是你的实际开销。
所以你的账户余额为 100 - 20 = 80 。

说明:

  • 0 <= purchaseAmount <= 100

思路

给我们100块钱购买商品,实际支出的金额需要四舍五入,例如商品金额为4,实际支付为0;商品金额为15,则需要支付20。求我们购物后的余额是多少。

回顾以下API:

  • Math.ceil 向上取整
  • Math.floor 向下取整
  • Math.round 四舍五入

如果我们不使用以上API的话如何实现呢?我们知道整数除法会舍去小数位,即向下取整的,因此我们可以将商品金额加5,如果需要支付的金额个位数大于等于5,加5之后会进位,而如果小于5,除法运算后也没影响。

官网题解还给出了分类讨论个位数的解法,先对10求余,如果余数小于5就舍去,否则就补到10进位。

代码

/**
 * @date 2024-06-12 8:39
 */
public class AccountBalanceAfterPurchase2806 {

    /**
     * 官网还有一种解法,分类讨论
     */
    public int accountBalanceAfterPurchase_v2(int purchaseAmount) {
        int r = purchaseAmount % 10;
        if (r < 5) {
            purchaseAmount -= r;
        } else {
            purchaseAmount += 10 - r;
        }
        return 100 - purchaseAmount;
    }

    /**
     * 网友题解,不使用Math库
     */
    public int accountBalanceAfterPurchase_v1(int purchaseAmount) {
        return 100 - (purchaseAmount + 5) / 10 * 10;
    }

    public int accountBalanceAfterPurchase(int purchaseAmount) {
        return 100 - (int) Math.round(purchaseAmount / 10.0) * 10;
    }

}

性能

3038.相同分数的最大操作数目I

目标

给你一个整数数组 nums ,如果 nums 至少 包含 2 个元素,你可以执行以下操作:

  • 选择 nums 中的前两个元素并将它们删除。

一次操作的 分数 是被删除元素的和。

在确保 所有操作分数相同 的前提下,请你求出 最多 能进行多少次操作。

请你返回按照上述要求 最多 可以进行的操作次数。

示例 1:

输入:nums = [3,2,1,4,5]
输出:2
解释:我们执行以下操作:
- 删除前两个元素,分数为 3 + 2 = 5 ,nums = [1,4,5] 。
- 删除前两个元素,分数为 1 + 4 = 5 ,nums = [5] 。
由于只剩下 1 个元素,我们无法继续进行任何操作。

示例 2:

输入:nums = [3,2,6,1,4]
输出:1
解释:我们执行以下操作:
- 删除前两个元素,分数为 3 + 2 = 5 ,nums = [6,1,4] 。
由于下一次操作的分数与前一次不相等,我们无法继续进行任何操作。

说明:

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

思路

按照题目模拟即可。

代码

/**
 * @date 2024-06-07 0:00
 */
public class MaxOperations3038 {
    public int maxOperations(int[] nums) {
        int cnt = 1;
        int n = nums.length;
        int i = 2;
        int score = nums[0] + nums[1];
        while (i < n - 1) {
            int tmp = nums[i] + nums[i + 1];
            if (tmp == score) {
                i += 2;
                cnt++;
            } else {
                break;
            }
        }
        return cnt;
    }
}

性能

1103.分糖果II

目标

排排坐,分糖果。

我们买了一些糖果 candies,打算把它们分给排好队的 n = num_people 个小朋友。

给第一个小朋友 1 颗糖果,第二个小朋友 2 颗,依此类推,直到给最后一个小朋友 n 颗糖果。

然后,我们再回到队伍的起点,给第一个小朋友 n + 1 颗糖果,第二个小朋友 n + 2 颗,依此类推,直到给最后一个小朋友 2 * n 颗糖果。

重复上述过程(每次都比上一次多给出一颗糖果,当到达队伍终点后再次从队伍起点开始),直到我们分完所有的糖果。注意,就算我们手中的剩下糖果数不够(不比前一次发出的糖果多),这些糖果也会全部发给当前的小朋友。

返回一个长度为 num_people、元素之和为 candies 的数组,以表示糖果的最终分发情况(即 ans[i] 表示第 i 个小朋友分到的糖果数)。

示例 1:

输入:candies = 7, num_people = 4
输出:[1,2,3,1]
解释:
第一次,ans[0] += 1,数组变为 [1,0,0,0]。
第二次,ans[1] += 2,数组变为 [1,2,0,0]。
第三次,ans[2] += 3,数组变为 [1,2,3,0]。
第四次,ans[3] += 1(因为此时只剩下 1 颗糖果),最终数组变为 [1,2,3,1]。

示例 2:

输入:candies = 10, num_people = 3
输出:[5,2,3]
解释:
第一次,ans[0] += 1,数组变为 [1,0,0]。
第二次,ans[1] += 2,数组变为 [1,2,0]。
第三次,ans[2] += 3,数组变为 [1,2,3]。
第四次,ans[0] += 4,最终数组变为 [5,2,3]。

说明:

  • 1 <= candies <= 10^9
  • 1 <= num_people <= 1000

思路

现在有一些糖果要分给一排小朋友,第一个小朋友分1个,第二个分2个,依次类推,即分配的糖果总比上一次分的多一个,如果不够就剩多少分多少。如果一轮下来没有分完,就接着从第一个小朋友开始依次分配。问最终每个小朋友能够分得的糖果数量。

我们可以很容易地模拟这个分配过程,记录当前分配的糖果数量,并计算剩余糖果数量直到0。

网友最快的题解使用了数学公式,使时间复杂度从O(num_people+sqrt(candies)) 降为O(num_people)。

代码

/**
 * @date 2024-06-03 0:06
 */
public class DistributeCandies1103 {

    public int[] distributeCandies_v1(int candies, int num_people) {
        int[] res = new int[num_people];
        // 足量发放人次,解不等式:(n+1)n/2 <= candies
        int n = (int) ((Math.sqrt(candies * 8F + 1) - 1) / 2);
        // 足量发放的糖果数量,num_people <= 1000,其实不会溢出
        int distributed = (int) ((1L + n) * n / 2);
        // 剩余糖数量
        int remainder = candies - distributed;
        // 所有小朋友都得到糖果的轮次
        int allGetLoops = n / num_people;
        // 最后一轮获得糖果的人数
        int lastLoopNum = n % num_people;
        for (int i = 0; i < num_people; i++) {
            // 收到糖果的次数 = 所有小朋友都得到糖果的轮次 + 最后一轮是否发放
            int times = (lastLoopNum > i ? 1 : 0) + allGetLoops;
            // 等差数列求和,公差为 num_people,a1 = i + 1,n = times;
            res[i] = ((times - 1) * num_people + i * 2 + 2) * times / 2;
        }
        // 如果是最后一个,将剩余的全部分配
        res[lastLoopNum] += remainder;
        return res;
    }

    public int[] distributeCandies(int candies, int num_people) {
        int[] res = new int[num_people];
        int cnt = 1;
        while (candies > 0) {
            for (int i = 0; i < num_people && candies > 0; i++) {
                int num = Math.min(cnt++, candies);
                candies -= num;
                res[i] += num;
            }
        }
        return res;
    }

}

性能