1015.可被K整除的最小整数

目标

给定正整数 k ,你需要找出可以被 k 整除的、仅包含数字 1 的最 小 正整数 n 的长度。

返回 n 的长度。如果不存在这样的 n ,就返回-1。

注意: n 可能不符合 64 位带符号整数。

示例 1:

输入:k = 1
输出:1
解释:最小的答案是 n = 1,其长度为 1。

示例 2:

输入:k = 2
输出:-1
解释:不存在可被 2 整除的正整数 n 。

示例 3:

输入:k = 3
输出:3
解释:最小的答案是 n = 111,其长度为 3。

说明:

  • 1 <= k <= 10^5

思路

求仅包含数字 1 且能够整除正整数 k 的数字的最小长度,如不存在返回 -1

通俗讲就是多长的 11111…… 能够整除 k。为了防止溢出可以只考虑余数,关键是停止条件是什么?如何确定是否存在?

如果余数出现重复,由于计算的式子不变,后续会陷入循环。可以使用哈希表记录出现过的余数。或者循环 k 次,由于余数的范围只可能是 0 ~ k - 1k 个,如果循环 k 次还没有使余数为 0,那么根据鸽巢原理一定存在重复的余数。

代码


/**
 * @date 2025-11-25 9:26
 */
public class SmallestRepunitDivByK1015 {

    public int smallestRepunitDivByK(int k) {
        if (k == 1) {
            return 1;
        }
        int res = 1;
        int num = 1;
        while (res < k) {
            num = (num * 10 + 1) % k;
            res++;
            if (num == 0) {
                return res;
            }
        }
        return -1;
    }
}

性能

1262.可被三整除的最大和

目标

给你一个整数数组 nums,请你找出并返回能被三整除的元素 最大和。

示例 1:

输入:nums = [3,6,5,1,8]
输出:18
解释:选出数字 3, 6, 1 和 8,它们的和是 18(可被 3 整除的最大和)。

示例 2:

输入:nums = [4]
输出:0
解释:4 不能被 3 整除,所以无法选出数字,返回 0。

示例 3:

输入:nums = [1,2,3,4,4]
输出:12
解释:选出数字 1, 3, 4 以及 4,它们的和是 12(可被 3 整除的最大和)。

说明:

  • 1 <= nums.length <= 4 * 10^4
  • 1 <= nums[i] <= 10^4

思路

求整数数组中元素的最大和,要求和能被 3 整除。

  • 如果和 sum % 3 == 1,可以去掉一个模 3 余 1 的最小元素,或者 两个模 3 余 2 的最小元素
  • 如果和 sum % 3 == 2,可以去掉一个模 3 余 2 的最小元素,或者 两个模 3 余 1 的最小元素

代码


/**
 * @date 2025-11-23 20:46
 */
public class MaxSumDivThree1262 {

    public int maxSumDivThree(int[] nums) {
        int res = 0;
        PriorityQueue<Integer> q1 = new PriorityQueue<>();
        PriorityQueue<Integer> q2 = new PriorityQueue<>();
        for (int num : nums) {
            res += num;
            if (num % 3 == 1) {
                q1.offer(num);
            } else if (num % 3 == 2) {
                q2.offer(num);
            }
        }
        int mod = res % 3;
        if (mod == 1) {
            int sub = q1.size() == 0 ? 100000 : q1.peek();
            if (q2.size() > 1) {
                sub = Math.min(sub, q2.poll() + q2.poll());
            }
            res -= sub;
        } else if (mod == 2) {
            int sub = q2.size() == 0 ? 100000 : q2.peek();
            if (q1.size() > 1) {
                sub = Math.min(sub, q1.poll() + q1.poll());
            }
            res -= sub;
        }
        return res;
    }
}

性能

1930.长度为3的不同回文子序列

目标

给你一个字符串 s ,返回 s 中 长度为 3 的不同回文子序列 的个数。

即便存在多种方法来构建相同的子序列,但相同的子序列只计数一次。

回文 是正着读和反着读一样的字符串。

子序列 是由原字符串删除其中部分字符(也可以不删除)且不改变剩余字符之间相对顺序形成的一个新字符串。

例如,"ace" 是 "abcde" 的一个子序列。

示例 1:

输入:s = "aabca"
输出:3
解释:长度为 3 的 3 个回文子序列分别是:
- "aba" ("aabca" 的子序列)
- "aaa" ("aabca" 的子序列)
- "aca" ("aabca" 的子序列)

示例 2:

输入:s = "adc"
输出:0
解释:"adc" 不存在长度为 3 的回文子序列。

示例 3:

输入:s = "bbcbaba"
输出:4
解释:长度为 3 的 4 个回文子序列分别是:
- "bbb" ("bbcbaba" 的子序列)
- "bcb" ("bbcbaba" 的子序列)
- "bab" ("bbcbaba" 的子序列)
- "aba" ("bbcbaba" 的子序列)

说明:

  • 3 <= s.length <= 10^5
  • s 仅由小写英文字母组成

思路

求长度为 3 的不同回文子序列个数。

枚举中间元素,同时枚举 a - z 作为左右两侧的字母,判断是否前后都存在。

对字母计数,在枚举过程中记录前面出现字母的次数,结合总次数可以快速判断后面是否存在相同的字母。注意,如果前面出现的字母与枚举的中间字母相同需要将次数减 1

代码


/**
 * @date 2025-11-21 8:44
 */
public class CountPalindromicSubsequence1930 {

    public int countPalindromicSubsequence_v1(String s) {
        int[] total = new int[26];
        char[] chars = s.toCharArray();
        for (char c : chars) {
            total[c - 'a']++;
        }
        boolean[][] visited = new boolean[26][26];
        int[] prefix = new int[26];
        int res = 0;
        for (char c : chars) {
            prefix[c - 'a']++;
            for (int j = 0; j < 26; j++) {
                if (!visited[j][c - 'a'] && total[j] > prefix[j] && ((j == c - 'a' && prefix[j] > 1) || j != c - 'a' && prefix[j] > 0)) {
                    visited[j][c - 'a'] = true;
                    res++;
                }
            }
        }
        return res;
    }

}

性能

1513.仅含1的子串数

目标

给你一个二进制字符串 s(仅由 '0' 和 '1' 组成的字符串)。

返回所有字符都为 1 的子字符串的数目。

由于答案可能很大,请你将它对 10^9 + 7 取模后返回。

示例 1:

输入:s = "0110111"
输出:9
解释:共有 9 个子字符串仅由 '1' 组成
"1" -> 5 次
"11" -> 3 次
"111" -> 1 次

示例 2:

输入:s = "101"
输出:2
解释:子字符串 "1" 在 s 中共出现 2 次

示例 3:

输入:s = "111111"
输出:21
解释:每个子字符串都仅由 '1' 组成

示例 4:

输入:s = "000"
输出:0

说明:

  • s[i] == '0' 或 s[i] == '1'
  • 1 <= s.length <= 10^5

思路

统计全一子串的个数。

根据等差数列求和公式计算即可。

代码


/**
 * @date 2025-11-16 22:17
 */
public class NumSub1513 {

    public int numSub(String s) {
        int mod = 1000000007;
        int n = s.length();
        int res = 0;
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == '0') {
                continue;
            }
            int start = i;
            while (i < n && s.charAt(i) == '1'){
                i++;
            }
            int cnt = i - start;
            res += ((cnt + 1L) * cnt / 2) % mod;

        }
        return res;
    }

}

性能

2536.子矩阵元素加1

目标

给你一个正整数 n ,表示最初有一个 n x n 、下标从 0 开始的整数矩阵 mat ,矩阵中填满了 0 。

另给你一个二维整数数组 queries 。针对每个查询 queries[i] = [row1i, col1i, row2i, col2i] ,请你执行下述操作:

  • 找出 左上角 为 (row1i, col1i) 且 右下角 为 (row2i, col2i) 的子矩阵,将子矩阵中的 每个元素 加 1 。也就是给所有满足 row1i <= x <= row2i 和 col1i <= y <= col2i 的 mat[x][y] 加 1 。

返回执行完所有操作后得到的矩阵 mat 。

示例 1:

输入:n = 3, queries = [[1,1,2,2],[0,0,1,1]]
输出:[[1,1,0],[1,2,1],[0,1,1]]
解释:上图所展示的分别是:初始矩阵、执行完第一个操作后的矩阵、执行完第二个操作后的矩阵。
- 第一个操作:将左上角为 (1, 1) 且右下角为 (2, 2) 的子矩阵中的每个元素加 1 。 
- 第二个操作:将左上角为 (0, 0) 且右下角为 (1, 1) 的子矩阵中的每个元素加 1 。 

示例 2:

输入:n = 2, queries = [[0,0,1,1]]
输出:[[1,1],[1,1]]
解释:上图所展示的分别是:初始矩阵、执行完第一个操作后的矩阵。 
- 第一个操作:将矩阵中的每个元素加 1 。

说明:

  • 1 <= n <= 500
  • 1 <= queries.length <= 10^4
  • 0 <= row1i <= row2i < n
  • 0 <= col1i <= col2i < n

思路

有一个元素值为 0n x n 矩阵 mat 和一系列由左上 (r1, c1) 右下 (r2, c2) 两个顶点表示的子矩阵,依次操作这些子矩阵,使其中的所有元素值加 1,返回最终得到的矩阵。

考察二维差分数组 以及 二维前缀和,这里直接当作多个一维差分处理了。

代码


/**
 * @date 2025-11-14 8:59
 */
public class RangeAddQueries2536 {

    public int[][] rangeAddQueries(int n, int[][] queries) {
        int[][] diff = new int[n][n + 1];
        for (int[] query : queries) {
            int row1 = query[0];
            int row2 = query[2];
            int col1 = query[1];
            int col2 = query[3];
            for (int j = row1; j <= row2; j++) {
                diff[j][col1]++;
                diff[j][col2 + 1]--;
            }
        }
        int[][] res = new int[n][n];
        for (int i = 0; i < n; i++) {
            int[] row = diff[i];
            res[i][0] = row[0];
            for (int j = 1; j < n; j++) {
                res[i][j] = res[i][j - 1] + row[j];
            }
        }
        return res;
    }

}

性能

3228.将1移动到末尾的最大操作次数

目标

给你一个 二进制字符串 s。

你可以对这个字符串执行 任意次 下述操作:

  • 选择字符串中的任一下标 i( i + 1 < s.length ),该下标满足 s[i] == '1' 且 s[i + 1] == '0'。
  • 将字符 s[i] 向 右移 直到它到达字符串的末端或另一个 '1'。例如,对于 s = "010010",如果我们选择 i = 1,结果字符串将会是 s = "000110"。

返回你能执行的 最大 操作次数。

示例 1:

输入: s = "1001101"
输出: 4
解释:
可以执行以下操作:
选择下标 i = 0。结果字符串为 s = "0011101"。
选择下标 i = 4。结果字符串为 s = "0011011"。
选择下标 i = 3。结果字符串为 s = "0010111"。
选择下标 i = 2。结果字符串为 s = "0001111"。

示例 2:

输入: s = "00111"
输出: 0

说明:

  • 1 <= s.length <= 10^5
  • s[i] 为 '0' 或 '1'。

思路

有一个二进制字符串 s,每次操作可以选择一个下标 i,满足 s[i] == '1's[i + 1] == '0',将 s[i] 向右移直到遇到另一个 1 或者到达末尾,返回可以执行的最大操作次数。

要使操作次数最大,每组相邻的 0 都要为其前面的 1 提供一次操作。换句话说操作尽量不要让右侧的 0 过早的合并,累加每组相邻的 0 前面 1 的个数即可。

计算前缀 1 个数,正序遍历,第一次遇到 0 时,就加上前面 1 的个数,跳过相邻的 0(因为每次操作都要移到最右侧,相邻的 0 对每个 1 只能贡献一次操作)。

代码


/**
 * @date 2025-11-13 8:44
 */
public class MaxOperations3228 {

    public int maxOperations(String s) {
        int n = s.length();
        char[] chars = s.toCharArray();
        int[] prefix = new int[n + 1];
        int res = 0;
        for (int i = 1; i <= n; i++) {
            prefix[i] = prefix[i - 1] + (chars[i - 1] - '0');
        }
        int i = 0;
        while (i < n) {
            if (chars[i] == '0') {
                res += prefix[i];
            }
            while (i < n && chars[i++] == '0') {
            }
        }
        return res;
    }

}

性能

2654.使数组所有元素变成1的最少操作次数

目标

给你一个下标从 0 开始的 正 整数数组 nums 。你可以对数组执行以下操作 任意 次:

  • 选择一个满足 0 <= i < n - 1 的下标 i ,将 nums[i] 或者 nums[i+1] 两者之一替换成它们的最大公约数。

请你返回使数组 nums 中所有元素都等于 1 的 最少 操作次数。如果无法让数组全部变成 1 ,请你返回 -1 。

两个正整数的最大公约数指的是能整除这两个数的最大正整数。

示例 1:

输入:nums = [2,6,3,4]
输出:4
解释:我们可以执行以下操作:
- 选择下标 i = 2 ,将 nums[2] 替换为 gcd(3,4) = 1 ,得到 nums = [2,6,1,4] 。
- 选择下标 i = 1 ,将 nums[1] 替换为 gcd(6,1) = 1 ,得到 nums = [2,1,1,4] 。
- 选择下标 i = 0 ,将 nums[0] 替换为 gcd(2,1) = 1 ,得到 nums = [1,1,1,4] 。
- 选择下标 i = 2 ,将 nums[3] 替换为 gcd(1,4) = 1 ,得到 nums = [1,1,1,1] 。

示例 2:

输入:nums = [2,10,6,14]
输出:-1
解释:无法将所有元素都变成 1 。

说明:

  • 2 <= nums.length <= 50
  • 1 <= nums[i] <= 10^6

思路

有一个正整数数组 nums,每次操作可以将 nums[i] 或者 nums[i + 1] 替换成它们的最大公约数。求将 nums 所有元素变为 1 的最小操作次数,如果无法完成,返回 -1

显然只要存在相邻的互质元素,就可以将其中的一个设置为 1,然后就可以将左右的元素按顺序替换为 1,总共需要操作 n 次。目标是如何用最小的操作次数使得存在一对相邻元素互质。暴力枚举 子数组 的起点与终点,计算所有元素的最大公约数,记录最小的子数组长度。

代码


/**
 * @date 2025-11-12 9:07
 */
public class MinOperations2654 {

    public int minOperations(int[] nums) {
        int n = nums.length;
        int res = Integer.MAX_VALUE;
        int oneCnt = 0;
        int gcdAll = nums[0];
        for (int num : nums) {
            if (num == 1) {
                oneCnt++;
            }
            gcdAll = gcd(gcdAll, num);
        }
        if (gcdAll > 1) {
            return -1;
        }
        if (oneCnt > 0) {
            return n - oneCnt;
        }
        for (int i = 0; i < n; i++) {
            int g = nums[i];
            for (int j = i; j < n; j++) {
                g = gcd(g, nums[j]);
                if (g == 1) {
                    res = Math.min(res, j - i + 1);
                    break;
                }
            }
        }
        return res - 2 + n;
    }

    public int gcd(int a, int b) {
        if (b == 0) {
            return a;
        }
        return gcd(b, a % b);
    }

}

性能

474.一和零

目标

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

示例 1:

输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
输出:4
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。
其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

示例 2:

输入:strs = ["10", "0", "1"], m = 1, n = 1
输出:2
解释:最大的子集是 {"0", "1"} ,所以答案是 2 。

说明:

  • 1 <= strs.length <= 600
  • 1 <= strs[i].length <= 100
  • strs[i] 仅由 '0' 和 '1' 组成
  • 1 <= m, n <= 100

思路

0- 1 背包问题的变种。

代码


/**
 * @date 2025-11-11 8:42
 */
public class FindMaxForm474 {

    public int findMaxForm(String[] strs, int m, int n) {
        int length = strs.length;
        int[][] cnt = new int[length][2];
        for (int i = 0; i < strs.length; i++) {
            String str = strs[i];
            for (char c : str.toCharArray()) {
                cnt[i][c - '0']++;
            }
        }
        int[][][] dp = new int[length][m + 1][n + 1];
        for (int i = cnt[0][0]; i <= m; i++) {
            for (int j = cnt[0][1]; j <= n; j++) {
                dp[0][i][j] = 1;
            }
        }
        for (int i = 1; i < length; i++) {
            for (int j = 0; j <= m; j++) {
                for (int k = 0; k <= n; k++) {
                    if (j >= cnt[i][0] && k >= cnt[i][1]) {
                        dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j - cnt[i][0]][k - cnt[i][1]] + 1);
                    } else {
                        dp[i][j][k] = dp[i - 1][j][k];
                    }
                }
            }
        }
        return dp[length - 1][m][n];
    }

}

性能

3542.将所有元素变为0的最少操作次数

目标

给你一个大小为 n 的 非负 整数数组 nums 。你的任务是对该数组执行若干次(可能为 0 次)操作,使得 所有 元素都变为 0。

在一次操作中,你可以选择一个子数组 [i, j](其中 0 <= i <= j < n),将该子数组中所有 最小的非负整数 的设为 0。

返回使整个数组变为 0 所需的最少操作次数。

一个 子数组 是数组中的一段连续元素。

示例 1:

输入: nums = [0,2]
输出: 1
解释:
选择子数组 [1,1](即 [2]),其中最小的非负整数是 2。将所有 2 设为 0,结果为 [0,0]。
因此,所需的最少操作次数为 1。

示例 2:

输入: nums = [3,1,2,1]
输出: 3
解释:
选择子数组 [1,3](即 [1,2,1]),最小非负整数是 1。将所有 1 设为 0,结果为 [3,0,2,0]。
选择子数组 [2,2](即 [2]),将 2 设为 0,结果为 [3,0,0,0]。
选择子数组 [0,0](即 [3]),将 3 设为 0,结果为 [0,0,0,0]。
因此,最少操作次数为 3。

示例 3:

输入: nums = [1,2,1,2,1,2]
输出: 4
解释:
选择子数组 [0,5](即 [1,2,1,2,1,2]),最小非负整数是 1。将所有 1 设为 0,结果为 [0,2,0,2,0,2]。
选择子数组 [1,1](即 [2]),将 2 设为 0,结果为 [0,0,0,2,0,2]。
选择子数组 [3,3](即 [2]),将 2 设为 0,结果为 [0,0,0,0,0,2]。
选择子数组 [5,5](即 [2]),将 2 设为 0,结果为 [0,0,0,0,0,0]。
因此,最少操作次数为 4。

说明:

  • 1 <= n == nums.length <= 10^5
  • 0 <= nums[i] <= 10^5

思路

有一个非负整数数组 nums,每一次操作可以任选一个子数组,将子数组的最小非负整数设为 0,求将整个数组变为 0 所需的最小操作次数。

保存元素值与下标的映射,同时记录已经变为 0 的元素下标,按照元素值从小到大的顺序枚举对应的下标,同时判断该下标后面是否有已变为 0 的下标。

代码


/**
 * @date 2025-11-10 8:53
 */
public class MinOperations3542 {

    public int minOperations(int[] nums) {
        TreeMap<Integer, List<Integer>> map = new TreeMap<>();
        TreeSet<Integer> zeros = new TreeSet<>();
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            int v = nums[i];
            if (v == 0) {
                zeros.add(i);
                continue;
            }
            map.putIfAbsent(v, new ArrayList<>());
            map.get(v).add(i);
        }
        int res = 0;
        for (Map.Entry<Integer, List<Integer>> entry : map.entrySet()) {
            if (zeros.size() == 0) {
                res++;
                zeros.addAll(entry.getValue());
                continue;
            }
            Integer right = null;
            for (Integer index : entry.getValue()) {
                if (right != null && index < right) {
                    continue;
                }
                res++;
                right = zeros.higher(index);
                if (right == null) {
                    break;
                }
            }
            zeros.addAll(entry.getValue());
        }
        return res;
    }

}

性能

3607.电网维护

目标

给你一个整数 c,表示 c 个电站,每个电站有一个唯一标识符 id,从 1 到 c 编号。

这些电站通过 n 条 双向 电缆互相连接,表示为一个二维数组 connections,其中每个元素 connections[i] = [ui, vi] 表示电站 ui 和电站 vi 之间的连接。直接或间接连接的电站组成了一个 电网 。

最初,所有 电站均处于在线(正常运行)状态。

另给你一个二维数组 queries,其中每个查询属于以下 两种类型之一 :

  • [1, x]:请求对电站 x 进行维护检查。如果电站 x 在线,则它自行解决检查。如果电站 x 已离线,则检查由与 x 同一 电网 中 编号最小 的在线电站解决。如果该电网中 不存在 任何 在线 电站,则返回 -1。
  • [2, x]:电站 x 离线(即变为非运行状态)。

返回一个整数数组,表示按照查询中出现的顺序,所有类型为 [1, x] 的查询结果。

注意:电网的结构是固定的;离线(非运行)的节点仍然属于其所在的电网,且离线操作不会改变电网的连接性。

示例 1:

输入: c = 5, connections = [[1,2],[2,3],[3,4],[4,5]], queries = [[1,3],[2,1],[1,1],[2,2],[1,2]]
输出: [3,2,3]
解释:
最初,所有电站 {1, 2, 3, 4, 5} 都在线,并组成一个电网。
查询 [1,3]:电站 3 在线,因此维护检查由电站 3 自行解决。
查询 [2,1]:电站 1 离线。剩余在线电站为 {2, 3, 4, 5}。
查询 [1,1]:电站 1 离线,因此检查由电网中编号最小的在线电站解决,即电站 2。
查询 [2,2]:电站 2 离线。剩余在线电站为 {3, 4, 5}。
查询 [1,2]:电站 2 离线,因此检查由电网中编号最小的在线电站解决,即电站 3。

示例 2:

输入: c = 3, connections = [], queries = [[1,1],[2,1],[1,1]]
输出: [1,-1]
解释:
没有连接,因此每个电站是一个独立的电网。
查询 [1,1]:电站 1 在线,且属于其独立电网,因此维护检查由电站 1 自行解决。
查询 [2,1]:电站 1 离线。
查询 [1,1]:电站 1 离线,且其电网中没有其他电站,因此结果为 -1。

说明:

  • 1 <= c <= 10^5
  • 0 <= n == connections.length <= min(10^5, c * (c - 1) / 2)
  • connections[i].length == 2
  • 1 <= ui, vi <= c
  • ui != vi
  • 1 <= queries.length <= 2 * 10^5
  • queries[i].length == 2
  • queries[i][0] 为 1 或 2。
  • 1 <= queries[i][1] <= c

思路

c 个电站,编号为 1 ~ cconnections[i] = [ui, vi] 表示电站 uivi 相连,所有连通的电站组成了一个电网。查询 queries[i] = [operation, x],如果 operation2 表示将电站 x 离线,如果 operation1 并且 x 在线,返回 x,否则返回 x 所在电网中在线电站的最小编号,如果没有在线电站返回 -1

使用 有序集合 数组 维护不同电网的在线电站。如果离线就将其从有序集合中删掉 O(logn),否则先判断集合是否为空,如果集合为空返回 -1,再判断电站是否在集合中 O(logn),如果在则直接返回查询电站编号,否则取集合最小的编号。

代码


/**
 * @date 2025-11-06 9:03
 */
public class ProcessQueries3607 {

    private class UnionFind {
        private int[] fa;

        public UnionFind() {
        }

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

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

        public void merge(int x, int y) {
            int a = find(x);
            int b = find(y);
            if (a != b) {
                fa[b] = a;
            }
        }

    }

    public int[] processQueries(int c, int[][] connections, int[][] queries) {
        UnionFind uf = new UnionFind(c + 1);
        for (int[] connection : connections) {
            uf.merge(connection[0], connection[1]);
        }
        TreeSet<Integer>[] set = new TreeSet[c + 1];
        Arrays.setAll(set, i -> new TreeSet<>());
        for (int i = 1; i <= c; i++) {
            set[uf.find(i)].add(i);
        }
        List<Integer> list = new ArrayList<>();
        boolean[] off = new boolean[c + 1];
        for (int[] query : queries) {
            int operation = query[0];
            int node = query[1];
            int network = uf.find(node);
            if (operation == 1) {
                if (set[network].size() > 0) {
                    if (off[node]) {
                        list.add(set[network].first());
                    } else {
                        list.add(node);
                    }
                } else {
                    list.add(-1);
                }
            } else {
                off[node] = true;
                set[network].remove(node);
            }
        }
        return list.stream().mapToInt(i -> i).toArray();
    }
}

性能