3289.数字小镇中的捣蛋鬼

目标

数字小镇 Digitville 中,存在一个数字列表 nums,其中包含从 0 到 n - 1 的整数。每个数字本应 只出现一次,然而,有 两个 顽皮的数字额外多出现了一次,使得列表变得比正常情况下更长。

为了恢复 Digitville 的和平,作为小镇中的名侦探,请你找出这两个顽皮的数字。

返回一个长度为 2 的数组,包含这两个数字(顺序任意)。

示例 1:

输入: nums = [0,1,1,0]
输出: [0,1]
解释:
数字 0 和 1 分别在数组中出现了两次。

示例 2:

输入: nums = [0,3,2,1,3,2]
输出: [2,3]
解释:
数字 2 和 3 分别在数组中出现了两次。

示例 3:

输入: nums = [7,1,5,4,3,4,6,0,9,5,8,2]
输出: [4,5]
解释:
数字 4 和 5 分别在数组中出现了两次。

说明:

  • 2 <= n <= 100
  • nums.length == n + 2
  • 0 <= nums[i] < n
  • 输入保证 nums 中 恰好 包含两个重复的元素。

思路

长度为 n + 2 的数组,其元素由 0 1 2 …… n - 1 n 个数字以及该范围内的两个任意数字组成,找出这两个重复数字。

简单的做法是对每个元素计数,找出出现次数为 2 的元素。但是空间复杂度为 O(n)

进阶的做法是使用位运算得到这两个重复数字的异或值,这两个数字至少有一个 bit 位不同,根据该 bit 位分组,最终得到这两个数字。

代码


/**
 * @date 2025-10-31 9:05
 */
public class GetSneakyNumbers3289 {

    public int[] getSneakyNumbers(int[] nums) {
        int n = nums.length;
        int[] cnt = new int[n];
        List<Integer> list = new ArrayList<>();
        for (int num : nums) {
            cnt[num]++;
            if (cnt[num] == 2){
                list.add(num);
            }
        }
        int[] res = new int[2];
        for (int i = 0; i < 2; i++) {
            res[i] = list.get(i);
        }
        return res;
    }
}

性能

1526.形成目标数组的子数组最少增加次数

目标

给你一个整数数组 target 和一个数组 initial ,initial 数组与 target 数组有同样的维度,且一开始全部为 0 。

请你返回从 initial 得到 target 的最少操作次数,每次操作需遵循以下规则:

  • 在 initial 中选择 任意 子数组,并将子数组中每个元素增加 1 。

答案保证在 32 位有符号整数以内。

示例 1:

输入:target = [1,2,3,2,1]
输出:3
解释:我们需要至少 3 次操作从 intial 数组得到 target 数组。
[0,0,0,0,0] 将下标为 0 到 4 的元素(包含二者)加 1 。
[1,1,1,1,1] 将下标为 1 到 3 的元素(包含二者)加 1 。
[1,2,2,2,1] 将下表为 2 的元素增加 1 。
[1,2,3,2,1] 得到了目标数组。

示例 2:

输入:target = [3,1,1,2]
输出:4
解释:(initial)[0,0,0,0] -> [1,1,1,1] -> [1,1,1,2] -> [2,1,1,2] -> [3,1,1,2] (target) 。

示例 3:

输入:target = [3,1,5,4,2]
输出:7
解释:(initial)[0,0,0,0,0] -> [1,1,1,1,1] -> [2,1,1,1,1] -> [3,1,1,1,1] 
                                  -> [3,1,2,2,2] -> [3,1,3,3,2] -> [3,1,4,4,2] -> [3,1,5,4,2] (target)。

示例 4:

输入:target = [1,1,1,1]
输出:1

说明:

  • 1 <= target.length <= 10^5
  • 1 <= target[i] <= 10^5

思路

有一个 target 数组和一个与其维度相同的的全 0 数组 initial,每次操作可以将 initial 任意子数组的每个元素加 1。求将 initial 变为 target 的最小操作次数。

将子数组全部加一很容易想到差分数组,按照贪心的思想,要将元素从 0 操作为 target[i] 一定需要 target[i] 次,问题在于有多少个元素可以共用这一个操作。

计算差分数组,仅统计其中大于 0 的部分,小于等于 0 说明可以公用前面的操作,大于 0 说明需要增加操作。

代码


/**
 * @date 2025-10-30 8:57
 */
public class MinNumberOperations1526 {

    public int minNumberOperations(int[] target) {
        int n = target.length;
        int res = target[0];
        for (int i = 1; i < n; i++) {
            int diff = target[i] - target[i - 1];
            if (diff > 0) {
                res += diff;
            }
        }
        return res;
    }
}

性能

3370.仅含置位位的最小整数

目标

给你一个正整数 n。

返回 大于等于 n 且二进制表示仅包含 置位 位的 最小 整数 x 。

置位 位指的是二进制表示中值为 1 的位。

示例 1:

输入: n = 5
输出: 7
解释:
7 的二进制表示是 "111"。

示例 2:

输入: n = 10
输出: 15
解释:
15 的二进制表示是 "1111"。

示例 3:

输入: n = 3
输出: 3
解释:
3 的二进制表示是 "11"。

说明:

  • 1 <= n <= 1000

思路

返回大于等于 n 并且所有 bit 位均为 1 的最小整数。

代码


/**
 * @date 2025-10-29 8:40
 */
public class SmallestNumber3370 {

    public int smallestNumber(int n) {
        int l = 32 - Integer.numberOfLeadingZeros(n);
        return (1 << l) - 1;
    }

}

性能

3354.使数组元素等于零

目标

给你一个整数数组 nums 。

开始时,选择一个满足 nums[curr] == 0 的起始位置 curr ,并选择一个移动 方向 :向左或者向右。

此后,你需要重复下面的过程:

  • 如果 curr 超过范围 [0, n - 1] ,过程结束。
  • 如果 nums[curr] == 0 ,沿当前方向继续移动:如果向右移,则 递增 curr ;如果向左移,则 递减 curr 。
  • 如果 nums[curr] > 0:
    • 将 nums[curr] 减 1 。
    • 反转 移动方向(向左变向右,反之亦然)。
    • 沿新方向移动一步。

如果在结束整个过程后,nums 中的所有元素都变为 0 ,则认为选出的初始位置和移动方向 有效 。

返回可能的有效选择方案数目。

示例 1:

输入:nums = [1,0,2,0,3]
输出:2
解释:
可能的有效选择方案如下:
选择 curr = 3 并向左移动。
[1,0,2,0,3] -> [1,0,2,0,3] -> [1,0,1,0,3] -> [1,0,1,0,3] -> [1,0,1,0,2] -> [1,0,1,0,2] -> [1,0,0,0,2] -> [1,0,0,0,2] -> [1,0,0,0,1] -> [1,0,0,0,1] -> [1,0,0,0,1] -> [1,0,0,0,1] -> [0,0,0,0,1] -> [0,0,0,0,1] -> [0,0,0,0,1] -> [0,0,0,0,1] -> [0,0,0,0,0].
选择 curr = 3 并向右移动。
[1,0,2,0,3] -> [1,0,2,0,3] -> [1,0,2,0,2] -> [1,0,2,0,2] -> [1,0,1,0,2] -> [1,0,1,0,2] -> [1,0,1,0,1] -> [1,0,1,0,1] -> [1,0,0,0,1] -> [1,0,0,0,1] -> [1,0,0,0,0] -> [1,0,0,0,0] -> [1,0,0,0,0] -> [1,0,0,0,0] -> [0,0,0,0,0].

示例 2:

输入:nums = [2,3,4,0,4,1,0]
输出:0
解释:
不存在有效的选择方案。

说明:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 100
  • 至少存在一个元素 i 满足 nums[i] == 0 。

思路

有一个数组 nums选一个元素值为 0 的位置作为起点,然后选择向左或向右移动,每遇到一个不为 0 的位置,将其元素值减一并沿相反方向继续移动,直到超出数组下标范围。求有多少种方案(由起点位置和初始移动方向唯一确定一个方案)可以使数组所有元素最终变为 0

计算数组的前后缀,如果左侧等于右侧,可以选两个方向,如果左右两侧相差 1,可以选一个方向。

代码


/**
 * @date 2025-10-28 8:49
 */
public class CountValidSelections3354 {

    public int countValidSelections(int[] nums) {
        int n = nums.length;
        int[] prefix = new int[n + 1];
        int[] suffix = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            prefix[i] = prefix[i - 1] + nums[i - 1];
            suffix[n - i] = suffix[n - i + 1] + nums[n - i];
        }
        int res = 0;
        for (int i = 0; i < n; i++) {
            if (nums[i] != 0) {
                continue;
            }
            if (prefix[i] == suffix[i + 1]) {
                res += 2;
            }
            if (prefix[i] == suffix[i + 1] + 1 || prefix[i] == suffix[i + 1] - 1) {
                res++;
            }
        }
        return res;
    }

}

性能

2125.银行中的激光束数量

目标

银行内部的防盗安全装置已经激活。给你一个下标从 0 开始的二进制字符串数组 bank ,表示银行的平面图,这是一个大小为 m x n 的二维矩阵。 bank[i] 表示第 i 行的设备分布,由若干 '0' 和若干 '1' 组成。'0' 表示单元格是空的,而 '1' 表示单元格有一个安全设备。

对任意两个安全设备而言,如果同时 满足下面两个条件,则二者之间存在 一个 激光束:

  • 两个设备位于两个 不同行 :r1 和 r2 ,其中 r1 < r2 。
  • 满足 r1 < i < r2 的 所有 行 i ,都 没有安全设备 。

激光束是独立的,也就是说,一个激光束既不会干扰另一个激光束,也不会与另一个激光束合并成一束。

返回银行中激光束的总数量。

示例 1:

输入:bank = ["011001","000000","010100","001000"]
输出:8
解释:在下面每组设备对之间,存在一条激光束。总共是 8 条激光束:
 * bank[0][1] -- bank[2][1]
 * bank[0][1] -- bank[2][3]
 * bank[0][2] -- bank[2][1]
 * bank[0][2] -- bank[2][3]
 * bank[0][5] -- bank[2][1]
 * bank[0][5] -- bank[2][3]
 * bank[2][1] -- bank[3][2]
 * bank[2][3] -- bank[3][2]
注意,第 0 行和第 3 行上的设备之间不存在激光束。
这是因为第 2 行存在安全设备,这不满足第 2 个条件。

示例 2:

输入:bank = ["000","111","000"]
输出:0
解释:不存在两个位于不同行的设备

提示:

  • m == bank.length
  • n == bank[i].length
  • 1 <= m, n <= 500
  • bank[i][j] 为 '0' 或 '1'

思路

跳过中间的空行,将相邻的非空行上的装置数量相乘。

代码


/**
 * @date 2025-10-27 10:34
 */
public class NumberOfBeams2125 {

    public int numberOfBeams(String[] bank) {
        int prev = 0, cur = 0;
        int res = 0;
        for (String b : bank) {
            for (char c : b.toCharArray()) {
                if (c == '1') {
                    cur++;
                }
            }
            if (cur == 0) {
                continue;
            }
            res += cur * prev;
            prev = cur;
            cur = 0;
        }
        return res;
    }

}

性能

2043.简易银行系统

目标

你的任务是为一个很受欢迎的银行设计一款程序,以自动化执行所有传入的交易(转账,存款和取款)。银行共有 n 个账户,编号从 1 到 n 。每个账号的初始余额存储在一个下标从 0 开始的整数数组 balance 中,其中第 (i + 1) 个账户的初始余额是 balance[i] 。

请你执行所有 有效的 交易。如果满足下面全部条件,则交易 有效 :

  • 指定的账户数量在 1 和 n 之间,且
  • 取款或者转账需要的钱的总数 小于或者等于 账户余额。

实现 Bank 类:

  • Bank(long[] balance) 使用下标从 0 开始的整数数组 balance 初始化该对象。
  • boolean transfer(int account1, int account2, long money) 从编号为 account1 的账户向编号为 account2 的账户转帐 money 美元。如果交易成功,返回 true ,否则,返回 false 。
  • boolean deposit(int account, long money) 向编号为 account 的账户存款 money 美元。如果交易成功,返回 true ;否则,返回 false 。
  • boolean withdraw(int account, long money) 从编号为 account 的账户取款 money 美元。如果交易成功,返回 true ;否则,返回 false 。

示例:

输入:
["Bank", "withdraw", "transfer", "deposit", "transfer", "withdraw"]
[[[10, 100, 20, 50, 30]], [3, 10], [5, 1, 20], [5, 20], [3, 4, 15], [10, 50]]
输出:
[null, true, true, true, false, false]

解释:
Bank bank = new Bank([10, 100, 20, 50, 30]);
bank.withdraw(3, 10);    // 返回 true ,账户 3 的余额是 $20 ,所以可以取款 $10 。
                         // 账户 3 余额为 $20 - $10 = $10 。
bank.transfer(5, 1, 20); // 返回 true ,账户 5 的余额是 $30 ,所以可以转账 $20 。
                         // 账户 5 的余额为 $30 - $20 = $10 ,账户 1 的余额为 $10 + $20 = $30 。
bank.deposit(5, 20);     // 返回 true ,可以向账户 5 存款 $20 。
                         // 账户 5 的余额为 $10 + $20 = $30 。
bank.transfer(3, 4, 15); // 返回 false ,账户 3 的当前余额是 $10 。
                         // 所以无法转账 $15 。
bank.withdraw(10, 50);   // 返回 false ,交易无效,因为账户 10 并不存在。

说明:

  • n == balance.length
  • 1 <= n, account, account1, account2 <= 10^5
  • 0 <= balance[i], money <= 10^12
  • transfer, deposit, withdraw 三个函数,每个 最多调用 10^4 次

思路

依题意模拟即可。

代码

class Bank {

    private long[] balance;

    public Bank(long[] balance) {
        this.balance = balance;
    }

    public boolean transfer(int account1, int account2, long money) {
        if (account1 > balance.length || account2 > balance.length || balance[account1 - 1] < money){
            return false;
        }
        balance[account1 - 1] -= money;
        balance[account2 - 1] += money;
        return true;
    }

    public boolean deposit(int account, long money) {
        if (account > balance.length){
            return false;
        }
        balance[account - 1] += money;
        return true;
    }

    public boolean withdraw(int account, long money) {
        if (account > balance.length || balance[account - 1] < money ){
            return false;
        }
        balance[account - 1] -= money;
        return true;
    }
}

/**
 * Your Bank object will be instantiated and called as such:
 * Bank obj = new Bank(balance);
 * boolean param_1 = obj.transfer(account1,account2,money);
 * boolean param_2 = obj.deposit(account,money);
 * boolean param_3 = obj.withdraw(account,money);
 */

性能

1716.计算力扣银行的钱

目标

Hercy 想要为购买第一辆车存钱。他 每天 都往力扣银行里存钱。

最开始,他在周一的时候存入 1 块钱。从周二到周日,他每天都比前一天多存入 1 块钱。在接下来每一个周一,他都会比 前一个周一 多存入 1 块钱。

给你 n ,请你返回在第 n 天结束的时候他在力扣银行总共存了多少块钱。

示例 1:

输入:n = 4
输出:10
解释:第 4 天后,总额为 1 + 2 + 3 + 4 = 10 。

示例 2:

输入:n = 10
输出:37
解释:第 10 天后,总额为 (1 + 2 + 3 + 4 + 5 + 6 + 7) + (2 + 3 + 4) = 37 。注意到第二个星期一,Hercy 存入 2 块钱。

示例 3:

输入:n = 20
输出:96
解释:第 20 天后,总额为 (1 + 2 + 3 + 4 + 5 + 6 + 7) + (2 + 3 + 4 + 5 + 6 + 7 + 8) + (3 + 4 + 5 + 6 + 7 + 8) = 96 。

说明:

  • 1 <= n <= 1000

思路

week 0 28 + 7 * 0
week 1 28 + 7 * 1
week 2 28 + 7 * 2
week 3 28 + 7 * 3
...

0 ~ n - 1 周的累加和 n * 28 + (n - 1) * n / 2 * 7

week n 1 + 2 + …… + rem       + n * rem
即     (rem * (rem + 1) / 2)  + n * rem
          当前周的前rem项和

代码


/**
 * @date 2025-10-25 22:11
 */
public class TotalMoney1716 {

    public int totalMoney(int n) {
        int oneWeek = 28;
        int times = n / 7;
        int rem = n % 7;
        return (1 + rem) * rem / 2 + times * oneWeek + Math.max(0, (times - 1) * times / 2) * 7 + times * rem;
    }

}

性能

2048.下一个更大的数值平衡数

目标

如果整数 x 满足:对于每个数位 d ,这个数位 恰好 在 x 中出现 d 次。那么整数 x 就是一个 数值平衡数 。

给你一个整数 n ,请你返回 严格大于 n 的 最小数值平衡数 。

示例 1:

输入:n = 1
输出:22
解释:
22 是一个数值平衡数,因为:
- 数字 2 出现 2 次 
这也是严格大于 1 的最小数值平衡数。

示例 2:

输入:n = 1000
输出:1333
解释:
1333 是一个数值平衡数,因为:
- 数字 1 出现 1 次。
- 数字 3 出现 3 次。 
这也是严格大于 1000 的最小数值平衡数。
注意,1022 不能作为本输入的答案,因为数字 0 的出现次数超过了 0 。

示例 3:

输入:n = 3000
输出:3133
解释:
3133 是一个数值平衡数,因为:
- 数字 1 出现 1 次。
- 数字 3 出现 3 次。 
这也是严格大于 3000 的最小数值平衡数。

说明:

  • 0 <= n <= 10^6

思路

定义平衡数中每一位上数字的出现次数 cnt[d] = d,判断大于 n 的最小平衡数。

回溯构造 10^7 范围内的所有平衡数,然后二分查找。

官网题解是枚举所有大于 n 的整数,判断是否是平衡数,也可以预处理 (n, 1224444] 范围内的所有平衡数,然后二分查找。

代码


/**
 * @date 2025-10-24 9:12
 */
public class NextBeautifulNumber2048 {

    public int nextBeautifulNumber(int n) {
        return set.higher(n);
    }

    private static final TreeSet<Integer> set = new TreeSet<>();

    static {
        int[] cnt = new int[7];
        Arrays.setAll(cnt, i -> i);
        dfs(0, 0, 7, cnt);
    }

    public static void dfs(int cur, int l, int length, int[] cnt) {
        if (l > length + 1) {
            return;
        }
        boolean balance = true;
        for (int i = 1; i < cnt.length; i++) {
            if (cnt[i] != i && cnt[i] != 0) {
                balance = false;
                break;
            }
        }
        if (balance) {
            set.add(cur);
        }
        for (int i = 1; i < cnt.length; i++) {
            if (cnt[i] == 0) {
                continue;
            }
            cnt[i]--;
            dfs(cur * 10 + i, l + 1, length, cnt);
            cnt[i]++;
        }
    }

}

性能

3461.判断操作后字符串中的数字是否相等I

目标

给你一个由数字组成的字符串 s 。重复执行以下操作,直到字符串恰好包含 两个 数字:

  • 从第一个数字开始,对于 s 中的每一对连续数字,计算这两个数字的和 模 10。
  • 用计算得到的新数字依次替换 s 的每一个字符,并保持原本的顺序。

如果 s 最后剩下的两个数字 相同 ,返回 true 。否则,返回 false。

示例 1:

输入: s = "3902"
输出: true
解释:
一开始,s = "3902"
第一次操作:
(s[0] + s[1]) % 10 = (3 + 9) % 10 = 2
(s[1] + s[2]) % 10 = (9 + 0) % 10 = 9
(s[2] + s[3]) % 10 = (0 + 2) % 10 = 2
s 变为 "292"
第二次操作:
(s[0] + s[1]) % 10 = (2 + 9) % 10 = 1
(s[1] + s[2]) % 10 = (9 + 2) % 10 = 1
s 变为 "11"
由于 "11" 中的数字相同,输出为 true。

示例 2:

输入: s = "34789"
输出: false
解释:
一开始,s = "34789"。
第一次操作后,s = "7157"。
第二次操作后,s = "862"。
第三次操作后,s = "48"。
由于 '4' != '8',输出为 false。

说明:

  • 3 <= s.length <= 100
  • s 仅由数字组成。

思路

有一个长度为 n 的数字字符串,每一次操作收集相邻两个数字之和模 10 的结果,得到一个长度为 n - 1 的字符串,反复执行操作直到剩下两个数字,判断剩余的两个数字是否相等。

简单的做法就是根据题意模拟。

n - 2 次合并后,s[i] 对最终结果的贡献等于从它开始,往下 n - 2 层到达根(可以看成一个倒着的杨辉三角)的路径数。

代码


/**
 * @date 2025-10-23 9:40
 */
public class HasSameDigits3461 {

    /**
     * 计算二项式展开系数
     */
    public boolean hasSameDigits_v1(String s) {
        int n = s.length();
        BigInteger[] factor = getFactor(n - 2);
        BigInteger a = BigInteger.ZERO;
        BigInteger b = BigInteger.ZERO;
        for (int i = 0; i < n - 1; i++) {
            a = a.add(BigInteger.valueOf(s.charAt(i) - '0').multiply(factor[i]));
        }
        for (int i = 1; i < n; i++) {
            b = b.add(BigInteger.valueOf(s.charAt(i) - '0').multiply(factor[i - 1]));
        }
        return a.mod(BigInteger.TEN).equals(b.mod(BigInteger.TEN));
    }

    public static Map<Integer, BigInteger[]> cache = new HashMap<>();

    public static BigInteger[] getFactor(int n) {
        BigInteger[] c = cache.get(n);
        if (c != null) {
            return c;
        }
        BigInteger[] prev = new BigInteger[1];
        prev[0] = BigInteger.ONE;
        for (int i = 1; i <= n; i++) {
            BigInteger[] cur = new BigInteger[i + 1];
            cur[0] = BigInteger.ONE;
            cur[i] = BigInteger.ONE;
            for (int j = 1; j < i; j++) {
                cur[j] = prev[j - 1].add(prev[j]);
            }
            prev = cur;
        }
        return prev;
    }

    /**
     * 模拟
     */
    public boolean hasSameDigits(String s) {
        Queue<Integer> q = new ArrayDeque<>();
        int n = s.length();
        for (int i = 0; i < n; i++) {
            q.offer(s.charAt(i) - '0');
        }
        while (q.size() > 2) {
            int len = q.size();
            int prev = q.poll();
            for (int i = 1; i < len; i++) {
                int cur = q.poll();
                q.offer((prev + cur) % 10);
                prev = cur;
            }
        }
        int a = q.poll();
        int b = q.poll();
        return a == b;
    }

}

性能

3347.执行操作后元素的最高频率II

目标

给你一个整数数组 nums 和两个整数 k 和 numOperations 。

你必须对 nums 执行 操作 numOperations 次。每次操作中,你可以:

  • 选择一个下标 i ,它在之前的操作中 没有 被选择过。
  • 将 nums[i] 增加范围 [-k, k] 中的一个整数。

在执行完所有操作以后,请你返回 nums 中出现 频率最高 元素的出现次数。

一个元素 x 的 频率 指的是它在数组中出现的次数。

示例 1:

输入:nums = [1,4,5], k = 1, numOperations = 2
输出:2
解释:
通过以下操作得到最高频率 2 :
将 nums[1] 增加 0 ,nums 变为 [1, 4, 5] 。
将 nums[2] 增加 -1 ,nums 变为 [1, 4, 4] 。

示例 2:

输入:nums = [5,11,20,20], k = 5, numOperations = 1
输出:2
解释:
通过以下操作得到最高频率 2 :
将 nums[1] 增加 0 。

说明:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9
  • 0 <= k <= 10^9
  • 0 <= numOperations <= nums.length

思路

对数组 nums 执行 numOperations 次操作,每次操作可以选一个没有被操作过的元素,将其增加 [-k, k] 之间的整数,求元素值的最大出现次数。

3346.执行操作后元素的最高频率I 相比,本题的数据范围更大,无法枚举值域。

考虑使用差分数组,由于数据范围太大,使用有序集合来维护。差分数组的前缀就是可以操作成该元素的频率,它不能超过原来已有的个数 + 操作次数。

代码


/**
 * @date 2025-10-21 10:34
 */
public class MaxFrequency3347 {

    public int maxFrequency(int[] nums, int k, int numOperations) {
        Map<Integer, Integer> cnt = new HashMap<>();
        Map<Integer, Integer> diff = new TreeMap<>();
        for (int num : nums) {
            cnt.merge(num, 1, Integer::sum);
            diff.putIfAbsent(num, 0);
            diff.merge(num - k, 1, Integer::sum);
            diff.merge(num + k + 1, -1, Integer::sum);
        }
        int res = 0;
        int frequency = 0;
        for (Map.Entry<Integer, Integer> entry : diff.entrySet()) {
            frequency += entry.getValue();
            res = Math.max(res, Math.min(frequency, cnt.getOrDefault(entry.getKey(), 0) + numOperations));
        }
        return res;
    }
}

性能