Skip to content

Commit bf8ccf9

Browse files
committed
第99场双周赛T1~T4 & 第335场周赛T1~T4 (8)
1 parent 13f533a commit bf8ccf9

17 files changed

+642
-0
lines changed

leetcode-01/src/main/java/Solution56.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,6 @@ public int[][] merge(int[][] intervals) {
6565
0 <= starti <= endi <= 10^4
6666
6767
排序后分三种情况合并区间即可。
68+
时间复杂度 O(nlogn)
69+
空间复杂度 O(logn)
6870
*/
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import java.util.ArrayList;
2+
import java.util.List;
3+
4+
public class Solution6307 {
5+
public int passThePillow(int n, int time) {
6+
// 构造一个周期
7+
List<Integer> list = new ArrayList<>();
8+
for (int i = 1; i <= n; i++) list.add(i);
9+
for (int i = n - 1; i > 1; i--) list.add(i);
10+
11+
int sz = list.size();
12+
return list.get(time % sz);
13+
}
14+
}
15+
/*
16+
6307. 递枕头
17+
https://leetcode.cn/problems/pass-the-pillow/
18+
19+
第 335 场周赛 T1。
20+
21+
n 个人站成一排,按从 1 到 n 编号。
22+
最初,排在队首的第一个人拿着一个枕头。每秒钟,拿着枕头的人会将枕头传递给队伍中的下一个人。一旦枕头到达队首或队尾,传递方向就会改变,队伍会继续沿相反方向传递枕头。
23+
- 例如,当枕头到达第 n 个人时,TA 会将枕头传递给第 n - 1 个人,然后传递给第 n - 2 个人,依此类推。
24+
给你两个正整数 n 和 time ,返回 time 秒后拿着枕头的人的编号。
25+
提示:
26+
2 <= n <= 1000
27+
1 <= time <= 1000
28+
29+
模拟。
30+
时间复杂度 O(n)
31+
*/
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import java.util.ArrayList;
2+
import java.util.Comparator;
3+
import java.util.LinkedList;
4+
import java.util.List;
5+
import java.util.Queue;
6+
7+
public class Solution6308 {
8+
public long kthLargestLevelSum(TreeNode root, int k) {
9+
List<Long> sumList = new ArrayList<>();
10+
11+
Queue<TreeNode> queue = new LinkedList<>();
12+
queue.add(root);
13+
while (!queue.isEmpty()) {
14+
int size = queue.size();
15+
long sum = 0L;
16+
for (int i = 0; i < size; i++) {
17+
TreeNode node = queue.remove();
18+
sum += node.val;
19+
if (node.left != null) {
20+
queue.add(node.left);
21+
}
22+
if (node.right != null) {
23+
queue.add(node.right);
24+
}
25+
}
26+
sumList.add(sum);
27+
}
28+
29+
// 第 K 大
30+
sumList.sort(Comparator.reverseOrder());
31+
return k - 1 < sumList.size() ? sumList.get(k - 1) : -1;
32+
}
33+
}
34+
/*
35+
6308. 二叉树中的第 K 大层和
36+
https://leetcode.cn/problems/kth-largest-sum-in-a-binary-tree/
37+
38+
第 335 场周赛 T2。
39+
40+
给你一棵二叉树的根节点 root 和一个正整数 k 。
41+
树中的 层和 是指 同一层 上节点值的总和。
42+
返回树中第 k 大的层和(不一定不同)。如果树少于 k 层,则返回 -1 。
43+
注意,如果两个节点与根节点的距离相同,则认为它们在同一层。
44+
提示:
45+
树中的节点数为 n
46+
2 <= n <= 10^5
47+
1 <= Node.val <= 10^6
48+
1 <= k <= n
49+
50+
层序遍历 + 排序
51+
时间复杂度 O(nlogn)
52+
*/
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import java.util.ArrayList;
2+
import java.util.HashMap;
3+
import java.util.List;
4+
import java.util.Map;
5+
6+
public class Solution6309 {
7+
public int findValidSplit(int[] nums) {
8+
int n = nums.length;
9+
Map<Integer, int[]> map = new HashMap<>();
10+
for (int i = 0; i < n; i++) {
11+
List<Integer> factorPrime = getFactorPrime(nums[i]);
12+
for (int x : factorPrime) {
13+
if (!map.containsKey(x)) {
14+
map.put(x, new int[]{i, i});
15+
} else {
16+
map.get(x)[1] = i;
17+
}
18+
}
19+
}
20+
21+
// f[i] 表示下标 starti 对应的最长 endi
22+
int[] f = new int[n];
23+
for (Map.Entry<Integer, int[]> entry : map.entrySet()) {
24+
int[] val = entry.getValue();
25+
f[val[0]] = val[1];
26+
}
27+
28+
// 能到达的最远距离下标,当前下标
29+
int maxR = 0, curR = 0;
30+
// [1, time) 返回所需片段的最小数目
31+
for (int i = 0; i < n - 1; i++) {
32+
maxR = Math.max(maxR, f[i]);
33+
if (i == curR) {
34+
if (i == maxR) {
35+
return i;
36+
}
37+
curR = maxR;
38+
}
39+
}
40+
return -1;
41+
}
42+
43+
private static List<Integer> getFactorPrime(int num) {
44+
List<Integer> resList = new ArrayList<>();
45+
for (int i = 2; i * i <= num; i++) {
46+
// 如果 i 能够整除 N,说明 i 为 N 的一个质因子。
47+
if (num % i == 0) {
48+
while (num % i == 0) {
49+
num /= i;
50+
}
51+
resList.add(i);
52+
}
53+
}
54+
// 说明再经过操作之后 N 留下了一个素数
55+
if (num != 1) {
56+
resList.add(num);
57+
}
58+
return resList;
59+
}
60+
}
61+
/*
62+
6309. 分割数组使乘积互质
63+
https://leetcode.cn/problems/split-the-array-to-make-coprime-products/
64+
65+
第 335 场周赛 T3。
66+
67+
给你一个长度为 n 的整数数组 nums ,下标从 0 开始。
68+
如果在下标 i 处 分割 数组,其中 0 <= i <= n - 2 ,使前 i + 1 个元素的乘积和剩余元素的乘积互质,则认为该分割 有效 。
69+
- 例如,如果 nums = [2, 3, 3] ,那么在下标 i = 0 处的分割有效,因为 2 和 9 互质,而在下标 i = 1 处的分割无效,因为 6 和 3 不互质。在下标 i = 2 处的分割也无效,因为 i == n - 1 。
70+
返回可以有效分割数组的最小下标 i ,如果不存在有效分割,则返回 -1 。
71+
当且仅当 gcd(val1, val2) == 1 成立时,val1 和 val2 这两个值才是互质的,其中 gcd(val1, val2) 表示 val1 和 val2 的最大公约数。
72+
提示:
73+
n == nums.length
74+
1 <= n <= 10^4
75+
1 <= nums[i] <= 10^6
76+
77+
分解质因数 + 贪心
78+
考虑每个质因数的 第一次出现下标 与 最后一次出现下标。然后类似跳跃游戏,看从下标 0 最远到达多远,这部分都是不能分割的。
79+
时间复杂度 O(n * √n)
80+
相似题目: 45. 跳跃游戏 II
81+
https://leetcode.cn/problems/jump-game-ii/
82+
*/
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
public class Solution6310 {
2+
private static final int MOD = (int) (1e9 + 7);
3+
4+
public int waysToReachTarget(int target, int[][] types) {
5+
// 多重背包 求方案数
6+
long[] f = new long[target + 1];
7+
f[0] = 1L;
8+
9+
for (int[] type : types) {
10+
for (int j = target; j >= type[1]; j--) {
11+
for (int k = 1; k <= type[0] && k * type[1] <= j; k++) {
12+
f[j] = (f[j] + f[j - k * type[1]]) % MOD;
13+
}
14+
}
15+
}
16+
return (int) f[target];
17+
}
18+
}
19+
/*
20+
6310. 获得分数的方法数
21+
https://leetcode.cn/problems/number-of-ways-to-earn-points/
22+
23+
第 335 场周赛 T4。
24+
25+
考试中有 n 种类型的题目。给你一个整数 target 和一个下标从 0 开始的二维整数数组 types ,其中 types[i] = [counti, marksi] 表示第 i 种类型的题目有 counti 道,每道题目对应 marksi 分。
26+
返回你在考试中恰好得到 target 分的方法数。由于答案可能很大,结果需要对 109 +7 取余。
27+
注意,同类型题目无法区分。
28+
- 比如说,如果有 3 道同类型题目,那么解答第 1 和第 2 道题目与解答第 1 和第 3 道题目或者第 2 和第 3 道题目是相同的。
29+
提示:
30+
1 <= target <= 1000
31+
n == types.length
32+
1 <= n <= 50
33+
types[i].length == 2
34+
1 <= counti, marksi <= 50
35+
36+
多重背包求方案数。
37+
时间复杂度 O(target * sum(count))
38+
*/
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
public class Solution6311 {
2+
public long coloredCells(int n) {
3+
long k = n * 2L - 1;
4+
return (k * k + 1) / 2;
5+
}
6+
}
7+
/*
8+
6311. 统计染色格子数
9+
https://leetcode.cn/problems/count-total-number-of-colored-cells/
10+
11+
第 99 场双周赛 T2。
12+
13+
有一个无穷大的二维网格图,一开始所有格子都未染色。给你一个正整数 n ,表示你需要执行以下步骤 n 分钟:
14+
- 第一分钟,将 任一 格子染成蓝色。
15+
- 之后的每一分钟,将与蓝色格子相邻的 所有 未染色格子染成蓝色。
16+
下图分别是 1、2、3 分钟后的网格图。
17+
请你返回 n 分钟之后 被染色的格子 数目。
18+
提示:
19+
1 <= n <= 10^5
20+
21+
找规律。
22+
时间复杂度 O(1)
23+
https://oeis.org/A001844
24+
*/
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import java.util.ArrayList;
2+
import java.util.List;
3+
import java.util.PriorityQueue;
4+
5+
public class Solution6312 {
6+
public int splitNum(int num) {
7+
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
8+
while (num > 0) {
9+
minHeap.add(num % 10);
10+
num /= 10;
11+
}
12+
13+
List<StringBuilder> sbs = new ArrayList<>();
14+
sbs.add(new StringBuilder());
15+
sbs.add(new StringBuilder());
16+
17+
int i = 0;
18+
while (!minHeap.isEmpty()) {
19+
sbs.get(i).append(minHeap.remove());
20+
i = 1 - i;
21+
}
22+
return Integer.parseInt(sbs.get(0).toString()) + Integer.parseInt(sbs.get(1).toString());
23+
}
24+
}
25+
/*
26+
6312. 最小和分割
27+
https://leetcode.cn/problems/split-with-minimum-sum/
28+
29+
第 99 场双周赛 T1。
30+
31+
给你一个正整数 num ,请你将它分割成两个非负整数 num1 和 num2 ,满足:
32+
- num1 和 num2 直接连起来,得到 num 各数位的一个排列。
33+
- 换句话说,num1 和 num2 中所有数字出现的次数之和等于 num 中所有数字出现的次数。
34+
- num1 和 num2 可以包含前导 0 。
35+
请你返回 num1 和 num2 可以得到的和的 最小 值。
36+
注意:
37+
- num 保证没有前导 0 。
38+
- num1 和 num2 中数位顺序可以与 num 中数位顺序不同。
39+
提示:
40+
10 <= num <= 10^9
41+
42+
贪心。
43+
时间复杂度 O(nlogn) 其中 n <= 9
44+
*/
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.List;
4+
5+
public class Solution6313 {
6+
private static final int MOD = (int) (1e9 + 7);
7+
8+
public int countWays(int[][] ranges) {
9+
// 连通块个数 k,答案为 2^k
10+
int k = merge(ranges);
11+
return (int) quickPow(2, k);
12+
}
13+
14+
private int merge(int[][] intervals) {
15+
// start 升序 end 降序
16+
Arrays.sort(intervals, (o1, o2) -> {
17+
if (o1[0] == o2[0]) {
18+
return Integer.compare(o2[1], o1[1]);
19+
}
20+
return Integer.compare(o1[0], o2[0]);
21+
});
22+
23+
int left = intervals[0][0];
24+
int right = intervals[0][1];
25+
List<int[]> resList = new ArrayList<>();
26+
for (int i = 1; i < intervals.length; i++) {
27+
int[] interval = intervals[i];
28+
if (left <= interval[0] && right >= interval[1]) {
29+
continue;
30+
}
31+
if (right >= interval[0] && right <= interval[1]) {
32+
right = interval[1];
33+
continue;
34+
}
35+
if (right < interval[0]) {
36+
resList.add(new int[]{left, right});
37+
left = interval[0];
38+
right = interval[1];
39+
}
40+
}
41+
resList.add(new int[]{left, right});
42+
return resList.size();
43+
}
44+
45+
// 模下的 a^b
46+
private long quickPow(long a, long b) {
47+
long res = 1L;
48+
while (b > 0) {
49+
if ((b & 1) == 1) {
50+
res = res * a % MOD;
51+
}
52+
a = a * a % MOD;
53+
b >>= 1;
54+
}
55+
return res;
56+
}
57+
}
58+
/*
59+
6313. 统计将重叠区间合并成组的方案数
60+
https://leetcode.cn/problems/count-ways-to-group-overlapping-ranges/
61+
62+
第 99 场双周赛 T3。
63+
64+
给你一个二维整数数组 ranges ,其中 ranges[i] = [starti, endi] 表示 starti 到 endi 之间(包括二者)的所有整数都包含在第 i 个区间中。
65+
你需要将 ranges 分成 两个 组(可以为空),满足:
66+
- 每个区间只属于一个组。
67+
- 两个有 交集 的区间必须在 同一个 组内。
68+
如果两个区间有至少 一个 公共整数,那么这两个区间是 有交集 的。
69+
- 比方说,区间 [1, 3] 和 [2, 5] 有交集,因为 2 和 3 在两个区间中都被包含。
70+
请你返回将 ranges 划分成两个组的 总方案数 。由于答案可能很大,将它对 109 + 7 取余 后返回。
71+
提示:
72+
1 <= ranges.length <= 10^5
73+
ranges[i].length == 2
74+
0 <= starti <= endi <= 10^9
75+
76+
合并区间 + 快速幂
77+
问题转换为有多少个连通块 k,答案为 2^k
78+
相似题目: 56. 合并区间
79+
https://leetcode.cn/problems/merge-intervals/
80+
2550. 猴子碰撞的方法数
81+
https://leetcode.cn/problems/count-collisions-of-monkeys-on-a-polygon/
82+
*/

0 commit comments

Comments
 (0)