Skip to content

Commit e1cb4c3

Browse files
committed
第432场周赛T1~T4 (4)
1 parent 27d7020 commit e1cb4c3

File tree

8 files changed

+382
-0
lines changed

8 files changed

+382
-0
lines changed
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+
4+
public class Solution3417 {
5+
public List<Integer> zigzagTraversal(int[][] grid) {
6+
int m = grid.length;
7+
int n = grid[0].length;
8+
9+
List<Integer> ans = new ArrayList<>();
10+
boolean add = true;
11+
for (int i = 0; i < m; i++) {
12+
for (int j = 0; j < n; j++) {
13+
if (add) {
14+
if (i % 2 == 0) ans.add(grid[i][j]);
15+
else ans.add(grid[i][n - 1 - j]);
16+
}
17+
add = !add;
18+
}
19+
}
20+
return ans;
21+
}
22+
}
23+
/*
24+
3417. 跳过交替单元格的之字形遍历
25+
https://leetcode.cn/problems/zigzag-grid-traversal-with-skip/description/
26+
27+
第 432 场周赛 T1。
28+
29+
给你一个 m x n 的二维数组 grid,数组由 正整数 组成。
30+
你的任务是以 之字形 遍历 grid,同时跳过每个 交替 的单元格。
31+
之字形遍历的定义如下:
32+
- 从左上角的单元格 (0, 0) 开始。
33+
- 在当前行中向 右 移动,直到到达该行的末尾。
34+
- 下移到下一行,然后在该行中向 左 移动,直到到达该行的开头。
35+
- 继续在行间交替向右和向左移动,直到所有行都被遍历完。
36+
注意:在遍历过程中,必须跳过每个 交替 的单元格。
37+
返回一个整数数组 result,其中包含按 顺序 记录的、且跳过交替单元格后的之字形遍历中访问到的单元格值。
38+
提示:
39+
2 <= n == grid.length <= 50
40+
2 <= m == grid[i].length <= 50
41+
1 <= grid[i][j] <= 2500
42+
43+
模拟。
44+
*/
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import java.util.Arrays;
2+
3+
public class Solution3418 {
4+
public int maximumAmount(int[][] coins) {
5+
int m = coins.length;
6+
int n = coins[0].length;
7+
8+
int[][][] f = new int[m][n][3];
9+
for (int i = 0; i < m; i++) {
10+
for (int j = 0; j < n; j++) {
11+
Arrays.fill(f[i][j], (int) -1e9);
12+
}
13+
}
14+
f[0][0][0] = coins[0][0]; // 感化0次
15+
f[0][0][1] = Math.max(0, f[0][0][0]); // 感化1次
16+
f[0][0][2] = Math.max(0, f[0][0][1]); // 感化2次
17+
for (int i = 0; i < m; i++) {
18+
for (int j = 0; j < n; j++) {
19+
for (int k0 = 0; k0 <= 2; k0++) {
20+
if (j - 1 >= 0) {
21+
f[i][j][k0] = Math.max(f[i][j][k0], f[i][j - 1][k0] + coins[i][j]);
22+
}
23+
if (i - 1 >= 0) {
24+
f[i][j][k0] = Math.max(f[i][j][k0], f[i - 1][j][k0] + coins[i][j]);
25+
}
26+
// 感化
27+
if (coins[i][j] >= 0) continue;
28+
int k1 = k0 + 1;
29+
if (k1 > 2) continue;
30+
if (j - 1 >= 0) {
31+
f[i][j][k1] = Math.max(f[i][j][k1], f[i][j - 1][k0]);
32+
}
33+
if (i - 1 >= 0) {
34+
f[i][j][k1] = Math.max(f[i][j][k1], f[i - 1][j][k0]);
35+
}
36+
}
37+
}
38+
}
39+
return Arrays.stream(f[m - 1][n - 1]).max().orElseThrow();
40+
}
41+
}
42+
/*
43+
3418. 机器人可以获得的最大金币数
44+
https://leetcode.cn/problems/maximum-amount-of-money-robot-can-earn/description/
45+
46+
第 432 场周赛 T2。
47+
48+
给你一个 m x n 的网格。一个机器人从网格的左上角 (0, 0) 出发,目标是到达网格的右下角 (m - 1, n - 1)。在任意时刻,机器人只能向右或向下移动。
49+
网格中的每个单元格包含一个值 coins[i][j]:
50+
- 如果 coins[i][j] >= 0,机器人可以获得该单元格的金币。
51+
- 如果 coins[i][j] < 0,机器人会遇到一个强盗,强盗会抢走该单元格数值的 绝对值 的金币。
52+
机器人有一项特殊能力,可以在行程中 最多感化 2个单元格的强盗,从而防止这些单元格的金币被抢走。
53+
注意:机器人的总金币数可以是负数。
54+
返回机器人在路径上可以获得的 最大金币数 。
55+
提示:
56+
m == coins.length
57+
n == coins[i].length
58+
1 <= m, n <= 500
59+
-1000 <= coins[i][j] <= 1000
60+
61+
网格图 DP。
62+
*/
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.List;
4+
5+
public class Solution3419 {
6+
private int n;
7+
private List<int[]>[] rg;
8+
private int[] vis;
9+
10+
public int minMaxWeight(int n, int[][] edges, int threshold) {
11+
this.n = n;
12+
rg = new ArrayList[n]; // 反图
13+
Arrays.setAll(rg, e -> new ArrayList<>());
14+
int maxWt = 0;
15+
for (int[] p : edges) {
16+
int u = p[0], v = p[1], wt = p[2];
17+
rg[v].add(new int[]{u, wt});
18+
maxWt = Math.max(maxWt, wt);
19+
}
20+
21+
vis = new int[n];
22+
int left = 0;
23+
int right = maxWt + 1;
24+
while (left < right) {
25+
int mid = left + (right - left) / 2;
26+
// 边界二分 F, F,..., F, [T, T,..., T]
27+
// ----------------------^
28+
if (checkMid(mid)) {
29+
right = mid;
30+
} else {
31+
left = mid + 1;
32+
}
33+
}
34+
return (left == maxWt + 1) ? -1 : left;
35+
}
36+
37+
private boolean checkMid(int mid) {
38+
return dfs(0, mid) == n;
39+
}
40+
41+
private int dfs(int x, int upper) {
42+
vis[x] = upper; // 避免每次重新创建 vis 数组
43+
int cnt = 1;
44+
for (int[] e : rg[x]) {
45+
int y = e[0];
46+
if (e[1] <= upper && vis[y] != upper) {
47+
cnt += dfs(y, upper);
48+
}
49+
}
50+
return cnt;
51+
}
52+
}
53+
/*
54+
3419. 图的最大边权的最小值
55+
https://leetcode.cn/problems/minimize-the-maximum-edge-weight-of-graph/description/
56+
57+
第 432 场周赛 T3。
58+
59+
给你两个整数 n 和 threshold ,同时给你一个 n 个节点的 有向 带权图,节点编号为 0 到 n - 1 。这个图用 二维 整数数组 edges 表示,其中 edges[i] = [Ai, Bi, Wi] 表示节点 Ai 到节点 Bi 之间有一条边权为 Wi的有向边。
60+
你需要从这个图中删除一些边(也可能 不 删除任何边),使得这个图满足以下条件:
61+
- 所有其他节点都可以到达节点 0 。
62+
- 图中剩余边的 最大 边权值尽可能小。
63+
- 每个节点都 至多 有 threshold 条出去的边。
64+
请你返回删除必要的边后,最大 边权的 最小值 为多少。如果无法满足所有的条件,请你返回 -1 。
65+
提示:
66+
2 <= n <= 10^5
67+
1 <= threshold <= n - 1
68+
1 <= edges.length <= min(105, n * (n - 1) / 2).
69+
edges[i].length == 3
70+
0 <= Ai, Bi < n
71+
Ai != Bi
72+
1 <= Wi <= 10^6
73+
一对节点之间 可能 会有多条边,但它们的权值互不相同。
74+
75+
二分答案。
76+
threshold 是多余的。请大胆二分。
77+
rating 2249 (clist.by)
78+
*/
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import java.util.ArrayDeque;
2+
import java.util.ArrayList;
3+
import java.util.Arrays;
4+
import java.util.Deque;
5+
import java.util.List;
6+
7+
public class Solution3420 {
8+
public long countNonDecreasingSubarrays(int[] nums, int k) {
9+
int n = nums.length;
10+
List<Integer>[] g = new ArrayList[n];
11+
Arrays.setAll(g, e -> new ArrayList<>());
12+
int[] posR = new int[n];
13+
Arrays.fill(posR, n);
14+
Deque<Integer> st = new ArrayDeque<>();
15+
for (int i = 0; i < n; i++) {
16+
int x = nums[i];
17+
while (!st.isEmpty() && x >= nums[st.peek()]) {
18+
posR[st.pop()] = i;
19+
}
20+
// 循环结束后,栈顶就是左侧 > x 的最近元素了
21+
if (!st.isEmpty()) {
22+
g[st.peek()].add(i);
23+
}
24+
st.push(i);
25+
}
26+
27+
long ans = 0;
28+
int cnt = 0;
29+
int l = 0; // 窗口左端点
30+
Deque<Integer> dq = new ArrayDeque<>(); // 单调队列维护最大值
31+
for (int r = 0; r < n; r++) { // 窗口右端点
32+
int x = nums[r];
33+
// x 进入窗口
34+
while (!dq.isEmpty() && nums[dq.peekLast()] <= x) {
35+
dq.pollLast(); // 维护 q 的单调性
36+
}
37+
dq.addLast(r);
38+
39+
// 由于队首到队尾单调递减,所以窗口最大值就是队首
40+
cnt += nums[dq.peekFirst()] - x;
41+
42+
// 操作次数太多,缩小窗口
43+
while (cnt > k) {
44+
int out = nums[l]; // 离开窗口的元素
45+
for (int i : g[l]) {
46+
if (i > r) {
47+
break;
48+
}
49+
cnt -= (out - nums[i]) * (Math.min(posR[i], r + 1) - i);
50+
}
51+
l++;
52+
53+
// 队首已经离开窗口了
54+
if (!dq.isEmpty() && dq.peekFirst() < l) {
55+
dq.pollFirst();
56+
}
57+
}
58+
59+
ans += r - l + 1;
60+
}
61+
62+
return ans;
63+
}
64+
}
65+
/*
66+
3420. 统计 K 次操作以内得到非递减子数组的数目
67+
https://leetcode.cn/problems/count-non-decreasing-subarrays-after-k-operations/description/
68+
69+
第 432 场周赛 T4。
70+
71+
给你一个长度为 n 的数组 nums 和一个整数 k 。
72+
对于 nums 中的每一个子数组,你可以对它进行 至多 k 次操作。每次操作中,你可以将子数组中的任意一个元素增加 1 。
73+
注意 ,每个子数组都是独立的,也就是说你对一个子数组的修改不会保留到另一个子数组中。
74+
请你返回最多 k 次操作以内,有多少个子数组可以变成 非递减 的。
75+
如果一个数组中的每一个元素都大于等于前一个元素(如果前一个元素存在),那么我们称这个数组是 非递减 的。
76+
提示:
77+
1 <= nums.length <= 10^5
78+
1 <= nums[i] <= 10^9
79+
1 <= k <= 10^9
80+
81+
单调栈+单调队列。
82+
左端点元素离开窗口 本题的难点。
83+
时间复杂度 O(n)。
84+
rating 2868 (clist.by)
85+
*/
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
import java.util.List;
5+
6+
public class Solution3417Tests {
7+
private final Solution3417 solution3417 = new Solution3417();
8+
9+
@Test
10+
public void example1() {
11+
int[][] grid = UtUtils.stringToInts2("[[1,2],[3,4]]");
12+
List<Integer> expected = List.of(1, 4);
13+
Assertions.assertEquals(expected, solution3417.zigzagTraversal(grid));
14+
}
15+
16+
@Test
17+
public void example2() {
18+
int[][] grid = UtUtils.stringToInts2("[[2,1],[2,1],[2,1]]");
19+
List<Integer> expected = List.of(2, 1, 2);
20+
Assertions.assertEquals(expected, solution3417.zigzagTraversal(grid));
21+
}
22+
23+
@Test
24+
public void example3() {
25+
int[][] grid = UtUtils.stringToInts2("[[1,2,3],[4,5,6],[7,8,9]]");
26+
List<Integer> expected = List.of(1, 3, 5, 7, 9);
27+
Assertions.assertEquals(expected, solution3417.zigzagTraversal(grid));
28+
}
29+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3418Tests {
5+
private final Solution3418 solution3418 = new Solution3418();
6+
7+
@Test
8+
public void example1() {
9+
int[][] coins = UtUtils.stringToInts2("[[0,1,-1],[1,-2,3],[2,-3,4]]");
10+
int expected = 8;
11+
Assertions.assertEquals(expected, solution3418.maximumAmount(coins));
12+
}
13+
14+
@Test
15+
public void example2() {
16+
int[][] coins = UtUtils.stringToInts2("[[10,10,10],[10,10,10]]");
17+
int expected = 40;
18+
Assertions.assertEquals(expected, solution3418.maximumAmount(coins));
19+
}
20+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3419Tests {
5+
private final Solution3419 solution3419 = new Solution3419();
6+
7+
@Test
8+
public void example1() {
9+
int n = 5;
10+
int[][] edges = UtUtils.stringToInts2("[[1,0,1],[2,0,2],[3,0,1],[4,3,1],[2,1,1]]");
11+
int threshold = 2;
12+
int expected = 1;
13+
Assertions.assertEquals(expected, solution3419.minMaxWeight(n, edges, threshold));
14+
}
15+
16+
@Test
17+
public void example2() {
18+
int n = 5;
19+
int[][] edges = UtUtils.stringToInts2("[[0,1,1],[0,2,2],[0,3,1],[0,4,1],[1,2,1],[1,4,1]]");
20+
int threshold = 1;
21+
int expected = -1;
22+
Assertions.assertEquals(expected, solution3419.minMaxWeight(n, edges, threshold));
23+
}
24+
25+
@Test
26+
public void example3() {
27+
int n = 5;
28+
int[][] edges = UtUtils.stringToInts2("[[1,2,1],[1,3,3],[1,4,5],[2,3,2],[3,4,2],[4,0,1]]");
29+
int threshold = 1;
30+
int expected = 2;
31+
Assertions.assertEquals(expected, solution3419.minMaxWeight(n, edges, threshold));
32+
}
33+
34+
@Test
35+
public void example4() {
36+
int n = 5;
37+
int[][] edges = UtUtils.stringToInts2("[[1,2,1],[1,3,3],[1,4,5],[2,3,2],[4,0,1]]");
38+
int threshold = 1;
39+
int expected = -1;
40+
Assertions.assertEquals(expected, solution3419.minMaxWeight(n, edges, threshold));
41+
}
42+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3420Tests {
5+
private final Solution3420 solution3420 = new Solution3420();
6+
7+
@Test
8+
public void example1() {
9+
int[] nums = {6, 3, 1, 2, 4, 4};
10+
int k = 7;
11+
long expected = 17;
12+
Assertions.assertEquals(expected, solution3420.countNonDecreasingSubarrays(nums, k));
13+
}
14+
15+
@Test
16+
public void example2() {
17+
int[] nums = {6, 3, 1, 3, 6};
18+
int k = 4;
19+
long expected = 12;
20+
Assertions.assertEquals(expected, solution3420.countNonDecreasingSubarrays(nums, k));
21+
}
22+
}

0 commit comments

Comments
 (0)