• LeetCode 309 周赛


    2399. 检查相同字母间的距离

    题目描述

    给你一个下标从 0 开始的字符串 s ,该字符串仅由小写英文字母组成,s 中的每个字母都 恰好 出现 两次 。另给你一个下标从 0 开始、长度为 26 的的整数数组 distance

    字母表中的每个字母按从 025 依次编号(即,'a' -> 0, 'b' -> 1, 'c' -> 2, … , 'z' -> 25)。

    在一个 匀整 字符串中,第 i 个字母的两次出现之间的字母数量是 distance[i] 。如果第 i 个字母没有在 s 中出现,那么 distance[i] 可以 忽略

    如果 s 是一个 匀整 字符串,返回 true ;否则,返回 false

    示例

    输入:s = "abaccb", distance = [1,3,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
    输出:true
    解释:
    - 'a' 在下标 0 和下标 2 处出现,所以满足 distance[0] = 1 。
    - 'b' 在下标 1 和下标 5 处出现,所以满足 distance[1] = 3 。
    - 'c' 在下标 3 和下标 4 处出现,所以满足 distance[2] = 0 。
    注意 distance[3] = 5 ,但是由于 'd' 没有在 s 中出现,可以忽略。
    因为 s 是一个匀整字符串,返回 true 。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    思路

    认真读题,简单模拟即可。使用一个Map进行存储,从左到右依次遍历每个字符,第一次遇见某个字符时,直接插入当前位置,第二次遇见时,计算中间间隔的字符数量即可。

    class Solution {
        public boolean checkDistances(String s, int[] distance) {
            int[] d = new int[26];
            Arrays.fill(d, -1);
            for (int i = 0; i < s.length(); i++) {
                int u = s.charAt(i) - 'a';
                if (d[u] == -1) d[u] = i; // 该字符第一次出现, 记录出现的下标
                else d[u] = i - 1 - d[u]; // 该字符第二次出现, 计算中间间隔的距离
            }
            
            for (int i = 0; i < distance.length; i++) {
                if (d[i] == -1) continue;
                if (d[i] != distance[i]) return false;
            }
            return true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2400. 恰好移动 k 步到达某一位置的方法数目

    题目描述

    给你两个 整数 startPosendPos 。最初,你站在 无限 数轴上位置 startPos 处。在一步移动中,你可以向左或者向右移动一个位置。

    给你一个正整数 k ,返回从 startPos 出发、恰好 移动 k 步并到达 endPos不同 方法数目。由于答案可能会很大,返回对 109 + 7 取余 的结果。

    如果所执行移动的顺序不完全相同,则认为两种方法不同。

    注意:数轴包含负整数

    • 1 <= startPos, endPos, k <= 1000

    示例

    输入:startPos = 1, endPos = 2, k = 3
    输出:3
    解释:存在 3 种从 1 到 2 且恰好移动 3 步的方法:
    - 1 -> 2 -> 3 -> 2.
    - 1 -> 2 -> 1 -> 2.
    - 1 -> 0 -> 1 -> 2.
    可以证明不存在其他方法,所以返回 3 。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    思路

    因为向左移动一次,可以和向右移动一次抵消。所以我们可以先算出startPosendPos的绝对距离,

    d = abs(startPos - endPos),我们可以先直接往一个方向移动d步,到达endPos,随后把剩余的步数平均分成往左移动一半的步数,和往右移动一半的步数。故,只有当k等于d加上一个偶数时,才能到达endPos

    我们不妨设endPos = startPos + d,即endPosstartPos右侧,距离为d

    我们设k = d + 2n,那么,我们需要往右移动d + n次,往左移动n次。问有多少种方案,其实就是个排列组合问题。

    我们将往右移动一次看成字符r,往左移动一次看成字符l。那么问题就变成了,给定d + n个字符r,以及n个字符l,问能够组成多少种不同的字符。由于不同的移动顺序会导致不同的方案,所以这其实是个排列问题。

    周赛时我采用的是DFS暴力,加上了记忆化的方式,来搜索方案数量。

    记忆化搜索

    class Solution {
        long ans = 0;
        int MOD = 1_000_000_000 + 7;
        long[][] dp; // 记忆化
        public int numberOfWays(int startPos, int endPos, int k) {
            int d = Math.abs(endPos - startPos); // 净距离
            if (k < d) return 0; // 不足d, 则肯定走不到
            k -= d;
            if ((k & 1) == 1) return 0; // 剩余的步数是奇数步, 则走不到
            int a = d + k / 2, b = k / 2;
            dp = new long[a + 1][b + 1];
            // 边界状态
            for (int i = 1; i <= b; i++) dp[0][i] = 1;
            for (int i = 1; i <= a; i++) dp[i][0] = 1;
            // 暴力搜索
            dfs(d + k / 2, k / 2);
            return (int) dp[a][b];
        }
        
        // a 表示还剩多少个字符a可以用
        // b 表示还剩多少个字符b可以用
        private long dfs(int a, int b) {
            // 其中一个字符用完了, 那么方案数为1
            if (a == 0 || b == 0) return 1;
            // 记忆化
            if (dp[a][b] != 0) return dp[a][b];
            // 具有对称性, 若dp[b][a] 求解出来了, 那么dp[a][b]也求出来了
            if (b < dp.length && a < dp[0].length && dp[b][a] != 0) {
                return dp[a][b] = dp[b][a];
            }
            // 当前这个位置取字符a或者取字符b
            dp[a][b] = dfs(a - 1, b) + dfs(a, b - 1);
            dp[a][b] = dp[a][b] % MOD;
            return dp[a][b];
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    二维DP(from yxc)

    这道题也可以用动态规划来做,一看数据范围1000,那么n^2的算法不会超时,可以考虑用n^2的算法来做。用二维DP,第一维存移动的步数,第二维存到达的位置的下标。这种想法不太好控制下标(因为会向左或向右移动,下标可能越界,实际编码时,可以将startPosendPos往右平移500,这样就算取到最值的情况下,也不会走到越界(往左能走到的最远距离,就是当startPos = endPos = 1, k = 1000,最多往左走到-500;往右能走到的最远,当startPos = endPos = 1000, k = 1000,最多往右走到1500,整个下标平移后,范围大概在[0, 2000]))。

    class Solution {
    
        int N = 2010, MOD = 1_000_000_000 + 7;
    
        // 第一维表示走了多少步, 第二维表示当前所在的下标
        // f表示方案数
        int[][] f = new int[1010][N];
    
        public int numberOfWays(int startPos, int endPos, int k) {
            startPos += 500;
            endPos += 500;
            f[0][startPos] = 1;
            for (int i = 1; i <= k; i++) {
                for (int j = 0; j < N; j++) {
                    // 能不能从j - 1转移过来
                    if (j > 0) f[i][j] = f[i - 1][j - 1];
                    // 能不能从j + 1转移过来
                    if (j + 1 < N) f[i][j] = (f[i][j] + f[i - 1][j + 1]) % MOD;
                }
            }
            return f[k][endPos];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    进阶:用乘法逆元来求组合数(from yxc)

    根据上面的分析,我们最终是求解这样一个问题,给定n个字符a,和m个字符b,将所有组合排列起来,问能组合成多少种不同的字符串。其实可以这样考虑这个问题,一共有m + n个位置,我们需要从中挑选出n个位置来放字符a,那剩余的位置就自动放了b,所以其实求解一个组合数 C m + n n C_{m+n}^n Cm+nn,对于组合数,我们可以用组合数公式来求解。但是这个过程可能会溢出,由于该题的模数 1 0 9 + 7 10^9 + 7 109+7 是个质数,故我们可以使用乘法逆元,将除法转换为乘法。

    根据欧拉定理的特例,费马小定理,当 p p p 是一个质数时,有 a p − 1 m o d    p = 1 a^{p-1} \mod p = 1 ap1modp=1

    a a a m o d    p \mod p modp 下的乘法逆元 a − 1 a^{-1} a1 ,满足 a × a − 1 m o d    p = 1 a × a^{-1} \mod p = 1 a×a1modp=1,容易推出 a − 1 = a p − 2 m o d    p a^{-1} = a^{p - 2} \mod p a1=ap2modp

    对任意的数 b b b,若 b b b 能整除 a a a,则有 b a m o d    p = b × a − 1 m o d    p \frac{b}{a} \mod p = b × a^{-1} \mod p abmodp=b×a1modp

    则我们对于组合数的分母上的每个数,求一下其逆元 a p − 2 m o d    p a^{p-2} \mod p ap2modp,将除法转化为乘法,而求解逆元的过程实际是个幂运算,故可以用快速幂算法。由于 p p p 的级别在 1 0 9 10^9 109 ,幂的次数是固定的 p − 2 p - 2 p2 ,我们近似地将其看成 p p p,则快速幂的运算次数( l o g p log{p} logp)大概在30次左右( 2 30 ≈ 1 0 9 2^{30} ≈ 10^9 230109),总的运算次数大概是 31 m 31m 31m(分子的运算次数 m m m,分母的运算次数 30 m 30m 30m),大概是线性复杂度了,非常快。

    这种用乘法逆元求解组合数的方法,几乎可以求解任意的组合数(非常快,数据也不会溢出)

    可以参考ACWING-算法基础课,第四章数学章节,求解组合数一共有大概4种解法:

    1. 利用递推公式 C n m = C n − 1 m + C n − 1 m − 1 C_n^m = C_{n-1}^m + C_{n-1}^{m-1} Cnm=Cn1m+Cn1m1 ,也就是利用DP
    2. 利用乘法逆元
    class Solution {
    
        int MOD = 1_000_000_000 + 7;
    
        public int numberOfWays(int startPos, int endPos, int k) {
            int d = Math.abs(startPos - endPos);
            if (d > k) return 0;
            k -= d;
            if ((k & 1) == 1) return 0;
            int a = d + k / 2, b = k / 2;
            int n = a + b, m = a;
            int res = 1;
            // 分子
            for (int i = n; i > n - m; i--) {
                res = (int) ((long) res * i % MOD);
            }
    
            // 分母
            for (int i = 1; i <= m; i++) {
                res = (int) ((long)res * qmi(i, MOD - 2, MOD) % MOD);
            }
            return res;
        }
    
        // 快速幂
        private int qmi(int a, int b, int p) {
            int res = 1;
            while (b > 0) {
                if ((b & 1) == 1) res = (int) ((long) res * a % p);
                a = (int) ((long)a * a % p);
                b >>= 1;
            }
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    2401. 最长优雅子数组

    题目描述

    给你一个由 整数组成的数组 nums

    如果 nums 的子数组中位于 不同 位置的每对元素按位 **与(AND)**运算的结果等于 0 ,则称该子数组为 优雅 子数组。

    返回 最长 的优雅子数组的长度。

    子数组 是数组中的一个 连续 部分。

    **注意:**长度为 1 的子数组始终视作优雅子数组。

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

    示例

    输入:nums = [1,3,8,48,10]
    输出:3
    解释:最长的优雅子数组是 [3,8,48] 。子数组满足题目条件:
    - 3 AND 8 = 0
    - 3 AND 48 = 0
    - 8 AND 48 = 0
    可以证明不存在更长的优雅子数组,所以返回 3 。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    思路

    求最长的长度,想到二分。对优雅子数组的定义:每对元素按位与的结果为0,这里要使用位运算。

    什么时候,一个子数组中的所有元素,两两做与,结果都是0呢。我们多举一些样例数据,就能发现。所有元素的1的位置,必须全部错开,才能保证两两相与都是0。

    可以先考虑2个数,按位与要得0,那么就不可能在某个位置,2个数都是1。即,一个数为1的位置,另一个数必须为0。

    比如,A中有5个位置为0,那么当考虑B时,B中最多只能在这5个位置上为1,;在考虑C时,A中为1和B中为1的位置,C都不能为1。考虑的数越多,能够取1的位置就越少。

    最后,所有数为1的位置,都是互相错开的。

    那么能够推出的一个判断条件是:

    • 把子数组中的每个数依次做按位与,得到的结果是0(我们把这个条件成为A

    但是注意,这个条件,只是必要条件,而不是充分条件,举个简单的例子。

    A=11001
    B=00110
    C=00110
    
    • 1
    • 2
    • 3

    很明显,B和C按位与的运算结果不为0,但由于A对应的位置为0,所以三个数做按位与的结果为0。

    那么如何表示这种1都是错开的关系呢?上面的数据,在满足A条件,但是不满足优雅子数组的定义的原因在于,有多个数字,在某个位置上为1,而只要有一个数字在这个位置上是0,就能使得整体的运算结果是0。所以,我们需要保证,竖着看时,在某一个位置上,只有一个数能够是1。那么在对于某个位置,把每个数在这个位置上的数字,做一下异或运算,以及或运算。若异或运算的结果和或运算的结果相等,则说明在每个位置上,都只有一个数是1。

    ----其实这个思路也有问题,再举一个反例,比如一共5个数,5个数在某一位置上的数如下

    0
    1
    0
    1
    0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    那么这一位置上的数做异或得1,做或 得1。然而实际这个位置上出现了多个1。

    再来想。我们把或运算换成加法运算。

    只有当每个位置上都只存在一个1时,做加法的结果,和做异或运算的结果相等。于是我们就用加法+异或这个条件,来判断优雅子数组。

    由于加法会产生进位,那么只有当每个位置上只有1个1时,加法运算的结果才和异或运算的一样。(其实这里也可以把异或运算替换为或运算)。

    **但是!**这道题我们要求最大长度,在二分长度的过程中,我们需要利用滑动窗口,窗口在滑动的过程中,当左侧端点滑出窗口,我们需要从运算结果中减去左侧被移出去的元素的值。

    这时!使用异或运算就有用武之地了!因为A ^ B ^ A = B,我们可以利用异或运算的这个性质,对窗口左侧移出的元素,的异或运算结果,进行恢复!而用或运算则做不到这一点。

    这里使用加法运算(和),以及异或运算,就能充分的判断是否是优雅子数组了。由于用到和,我们预处理一下,得到前缀和数组。

    所以最终的思路就是:二分+滑动窗口+前缀和+位运算

    class Solution {
        
        long[] preSum;
        
    	public int longestNiceSubarray(int[] nums) {
    		int ans = 1;
            
            preSum = new long[nums.length + 1];
            for (int i = 1; i <= nums.length; i++) preSum[i] = preSum[i - 1] + nums[i - 1];
            
    		// 二分长度
    		int l = 1, r = nums.length;
    		while (l < r) {
    			int mid = l + r + 1>> 1;
    			if (check(nums, mid)) l = mid;
    			else r = mid - 1;
    		}
    		return l;
    	}
    
    	// 该数组中是否存在长度为len的优雅子数组
    	private boolean check(int[] nums, int len) {
            
            // 滑动窗口
            int t1 = -1;
            for (int i = 0, j = 0; i < nums.length; i++) {
                if (i == 0) t1 = nums[i];
                else t1 = t1 ^ nums[i];
                if (i - j + 1 == len) {
                    if (t1 == (int) (preSum[i + 1] - preSum[j])) return true;
                    // 把 j 去掉
                    t1 = t1 ^ nums[j]; // 异或运算能恢复
                    j++;
                }
            }
            return false;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    其实后面发现,不用二分长度,直接一次滑动窗口就行了(汗 -_-||)

    滑动窗口1(from yxc)

    思路也是类似,只要保证某个子数组中,在每个位置最多中出现一个1即可,这里由于数据范围最大是10^9,即最大有30位左右,我们直接对每个数,统计其每个位置上的1即可。

    class Solution {
        public int longestNiceSubarray(int[] nums) {
            int[] cnt = new int[40]; // 每个位置上1的出现次数
            int total = 0; // 出现1的次数超过1的位置的数量
            int ans = 0;
            for (int i = 0, j = 0; i < nums.length; i++) {
                for (int k = 0; k < 31; k++) {
                    if ((nums[i] >> k & 1) == 1) {
                        if (cnt[k] == 1) total++; // 这个位置上的1的数量第一次超过1
                        cnt[k]++;
                    }
                }
                while (total > 0) {
                    // 当存在一个位置上出现多个1时, 右移j
                    for (int k = 0; k < 31; k++) {
                        if ((nums[j] >> k & 1) == 1) {
                            cnt[k]--;
                            if (cnt[k] == 1) total--; // 这个位置上的1第一次降为1
                        }
                    }
                    j++;
                }
                ans = Math.max(ans, i - j + 1);
            }
            return ans;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    滑动窗口2(位运算)

    使用位运算,而不是每个位置依次统计

    class Solution {
        public int longestNiceSubarray(int[] nums) {
            int state = 0, ans = 0;
            for (int i = 0, j = 0; i < nums.length; i++) {
                while ((state & nums[i]) != 0) {
                    // 当前i无法加入状态, 右移j
                    state ^= nums[j];
                    j++;
                }
                state ^= nums[i];
                ans = Math.max(ans, i - j + 1);
            }
            return ans;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2402. 会议室III

    题目描述

    给你一个整数 n ,共有编号从 0n - 1n 个会议室。

    给你一个二维整数数组 meetings ,其中 meetings[i] = [starti, endi] 表示一场会议将会在 半闭 时间区间 [starti, endi) 举办。所有 starti 的值 互不相同

    会议将会按以下方式分配给会议室:

    1. 每场会议都会在未占用且编号 最小 的会议室举办。
    2. 如果没有可用的会议室,会议将会延期,直到存在空闲的会议室。延期会议的持续时间和原会议持续时间 相同
    3. 当会议室处于未占用状态时,将会优先提供给原 开始 时间更早的会议。

    返回举办最多次会议的房间 编号 。如果存在多个房间满足此条件,则返回编号 最小 的房间。

    半闭区间 [a, b)ab 之间的区间,包括 a不包括 b

    示例

    输入:n = 2, meetings = [[0,10],[1,5],[2,7],[3,4]]
    输出:0
    解释:
    - 在时间 0 ,两个会议室都未占用,第一场会议在会议室 0 举办。
    - 在时间 1 ,只有会议室 1 未占用,第二场会议在会议室 1 举办。
    - 在时间 2 ,两个会议室都被占用,第三场会议延期举办。
    - 在时间 3 ,两个会议室都被占用,第四场会议延期举办。
    - 在时间 5 ,会议室 1 的会议结束。第三场会议在会议室 1 举办,时间周期为 [5,10) 。
    - 在时间 10 ,两个会议室的会议都结束。第四场会议在会议室 0 举办,时间周期为 [10,11) 。
    会议室 0 和会议室 1 都举办了 2 场会议,所以返回 0 。 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    思路

    感觉有点像区间合并的问题。就把整个过程模拟一下。我脑子里的思路大概是:对n个会议室,维护一下这个会议室的会议的结束时间。当所有会议室都被占用时,结束时间最早的会议室,应该要安排给下一个等待的会议。同样,对于等待的会议,需要取出开始时间最早的会议。这样,就用两个堆来实现即可。

    先将会议按照开始时间从小到大排序。因为我们总是会尽可能安排开始时间早的会议。

    一定要一个堆维护当前空闲的会议室,空闲的会议室不需要考虑该会议室的结束时间;另一个堆要维护当前正在使用的会议室,当轮到某个会议召开时,若当前有空闲会议室,则直接从空闲会议室中挑一个编号最小的;若当前无空闲会议室,则需要从已被使用的会议室中,找到一个结束时间最早的,若有多个结束时间最早的会议室,则要选编号最小的(双关键字排序)。

    class Solution {
    
    	class Pair {
    		long end;
    		int no;
    		Pair(long end, int no) {
    			this.end = end;
    			this.no = no;
    		}
    	}
    
    	public int mostBooked(int n, int[][] meetings) {
    		// 先按照区间左端点排序
    		quickSort(meetings, 0, meetings.length - 1);
            // 这里排序可以替换为 Arrays.sort(meetings, (a, b) -> a[0] - b[0]);
    		int[] cnt = new int[n];
    		// 空闲的会议室
    		PriorityQueue<Integer> free = new PriorityQueue<>();
            // 已使用的会议室, 按照结束时间, 会议室编号, 进行双关键字排序!注意!
    		PriorityQueue<Pair> used = new PriorityQueue<>((o1, o2) -> {
    			if (o1.end < o2.end) return -1;
    			if (o1.end == o2.end) return o1.no - o2.no;
    			return 1;
    		});
    		// 初始化, 将全部会议室放到空闲当中
    		for (int i = 0; i < n; i++) free.offer(i);
    		for (int i = 0; i < meetings.length; i++) {
    			int start = meetings[i][0], end = meetings[i][1];
    			// 如果轮到当前会议时, 有某个会议室已经使用完毕, 则要释放出来
    			while (used.size() > 0 && used.peek().end <= start) {
    				Pair p = used.poll();
    				free.offer(p.no);
    			}
    			if (free.size() > 0) {
    				// 有空闲的会议室, 则直接使用
    				int x = free.poll();
    				used.offer(new Pair((long) end, x));
    				cnt[x]++;
    			} else {
    				// 没有, 则从被占用的会议室中选出结束时间最早的, 结束时间相同则选编号最小的
    				Pair p = used.poll();
    				used.offer(new Pair(p.end + end - start, p.no));
    				cnt[p.no]++;
    			}
    		}
    		int ans = 0;
    		for (int i = 0; i < n; i++) {
    			if (cnt[i] > cnt[ans]) {
    				ans = i;
    			}
    		}
    		return ans;
    	}
    
    	private void quickSort(int[][] arr, int l, int r) {
    		if (l >= r) return ;
    		int x = arr[l + r >> 1][0], i = l - 1, j = r + 1;
    		while (i < j) {
    			do i++; while (arr[i][0] < x);
    			do j--; while (arr[j][0] > x);
    			if (i < j) {
    				int[] t = arr[i];
    				arr[i] = arr[j];
    				arr[j] = t;
    			}
    		}
    		quickSort(arr, l, j);
    		quickSort(arr, j + 1, r);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    总结

    这次周赛的结果比较满意,第二题和第三题难度都不小,但都做出来了,虽然时间花的比较长。

    再接再厉!

  • 相关阅读:
    关于electron打包卡在winCodeSign下载问题
    Linux常见指令2
    Estimator::relativePose
    程序员个性终端指南(cmder、powershell、window terminal)
    【P58】JMeter 简单数据写入器(Simple Data Writer)
    Java基础(二十六):正则表达式
    微信小程序 prettier 格式化
    如何成为 10 倍软件工程师
    【面经】讲一下你对jvm和jmm的了解
    【MyBatis】MyBatis日志信息配置
  • 原文地址:https://blog.csdn.net/vcj1009784814/article/details/126843568