Skip to content

Commit 86e0c5b

Browse files
committed
第156场双周赛T1~T4 & 第449场周赛T1~T4 (8)
1 parent ef60d94 commit 86e0c5b

16 files changed

+761
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
public class Solution3541 {
2+
// final int VOWEL_MASK = (1 << ('a' - 'a')) | (1 << ('e' - 'a')) | (1 << ('i' - 'a')) | (1 << ('o' - 'a')) | (1 << ('u' - 'a'));
3+
private static final int VOWEL_MASK = 1065233;
4+
5+
public int maxFreqSum(String s) {
6+
int[] cnt = new int[26];
7+
for (char c : s.toCharArray()) {
8+
cnt[c - 'a']++;
9+
}
10+
int mx1 = 0, mx2 = 0;
11+
for (int i = 0; i < 26; i++) {
12+
if (isVowel(i)) {
13+
mx1 = Math.max(mx1, cnt[i]);
14+
} else {
15+
mx2 = Math.max(mx2, cnt[i]);
16+
}
17+
}
18+
return mx1 + mx2;
19+
}
20+
21+
private boolean isVowel(int b) {
22+
return (VOWEL_MASK >> b & 1) == 0;
23+
}
24+
}
25+
/*
26+
3541. 找到频率最高的元音和辅音
27+
https://leetcode.cn/problems/find-most-frequent-vowel-and-consonant/description/
28+
29+
第 156 场双周赛 T1。
30+
31+
给你一个由小写英文字母('a' 到 'z')组成的字符串 s。你的任务是找出出现频率 最高 的元音('a'、'e'、'i'、'o'、'u' 中的一个)和出现频率最高的辅音(除元音以外的所有字母),并返回这两个频率之和。
32+
注意:如果有多个元音或辅音具有相同的最高频率,可以任选其中一个。如果字符串中没有元音或没有辅音,则其频率视为 0。
33+
一个字母 x 的 频率 是它在字符串中出现的次数。
34+
提示:
35+
1 <= s.length <= 100
36+
s 只包含小写英文字母
37+
38+
模拟。
39+
*/
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import java.util.ArrayDeque;
2+
import java.util.Deque;
3+
4+
public class Solution3542 {
5+
static class V1 {
6+
public int minOperations(int[] nums) {
7+
int ans = 0;
8+
Deque<Integer> st = new ArrayDeque<>();
9+
for (int x : nums) {
10+
while (!st.isEmpty() && x < st.peek()) {
11+
st.pop();
12+
ans++;
13+
}
14+
// 如果 x 与栈顶相同,那么 x 与栈顶可以在同一次操作中都变成 0,x 无需入栈
15+
if (st.isEmpty() || x != st.peek()) {
16+
st.push(x);
17+
}
18+
}
19+
return ans + st.size() - (st.getLast() == 0 ? 1 : 0); // 0 不需要操作
20+
}
21+
}
22+
23+
static class V2 {
24+
public int minOperations(int[] nums) {
25+
int ans = 0;
26+
int top = -1; // 栈顶下标(把 nums 当作栈)
27+
for (int x : nums) {
28+
while (top >= 0 && x < nums[top]) {
29+
top--; // 出栈
30+
ans++;
31+
}
32+
// 如果 x 与栈顶相同,那么 x 与栈顶可以在同一次操作中都变成 0,x 无需入栈
33+
if (top < 0 || x != nums[top]) {
34+
nums[++top] = x; // 入栈
35+
}
36+
}
37+
return ans + top + (nums[0] > 0 ? 1 : 0);
38+
}
39+
}
40+
}
41+
/*
42+
3542. 将所有元素变为 0 的最少操作次数
43+
https://leetcode.cn/problems/minimum-operations-to-convert-all-elements-to-zero/description/
44+
45+
第 156 场双周赛 T2。
46+
47+
给你一个大小为 n 的 非负 整数数组 nums 。你的任务是对该数组执行若干次(可能为 0 次)操作,使得 所有 元素都变为 0。
48+
在一次操作中,你可以选择一个子数组 [i, j](其中 0 <= i <= j < n),将该子数组中所有 最小的非负整数 的设为 0。
49+
返回使整个数组变为 0 所需的最少操作次数。
50+
一个 子数组 是数组中的一段连续元素。
51+
提示:
52+
1 <= n == nums.length <= 10^5
53+
0 <= nums[i] <= 10^5
54+
55+
赛时没做出来。。
56+
单调栈。
57+
https://leetcode.cn/problems/minimum-operations-to-convert-all-elements-to-zero/solutions/3673804/cong-fen-zhi-dao-dan-diao-zhan-jian-ji-x-mzbl/
58+
rating 1822 (clist.by)
59+
*/
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.HashSet;
4+
import java.util.List;
5+
import java.util.Set;
6+
7+
public class Solution3543 {
8+
private List<int[]>[] g;
9+
private int k, t, ans;
10+
private Set<String> memo;
11+
12+
public int maxWeight(int n, int[][] edges, int k, int t) {
13+
g = new ArrayList[n];
14+
Arrays.setAll(g, e -> new ArrayList<>());
15+
for (int[] e : edges) {
16+
g[e[0]].add(new int[]{e[1], e[2]}); // y, wt
17+
}
18+
this.k = k;
19+
this.t = t;
20+
21+
memo = new HashSet<>();
22+
ans = -1;
23+
for (int x = 0; x < n; x++) {
24+
dfs(x, 0, 0);
25+
}
26+
return ans;
27+
}
28+
29+
private void dfs(int x, int i, int s) {
30+
String key = x + ":" + i + ":" + s;
31+
if (!memo.add(key)) return;
32+
if (i == k) {
33+
ans = Math.max(ans, s);
34+
return;
35+
}
36+
for (int[] p : g[x]) {
37+
int y = p[0], wt = p[1];
38+
if (s + wt < t) {
39+
dfs(y, i + 1, s + wt);
40+
}
41+
}
42+
}
43+
}
44+
/*
45+
3543. K 条边路径的最大边权和
46+
https://leetcode.cn/problems/maximum-weighted-k-edge-path/description/
47+
48+
第 156 场双周赛 T3。
49+
50+
给你一个整数 n 和一个包含 n 个节点(编号从 0 到 n - 1)的 有向无环图(DAG)。该图由二维数组 edges 表示,其中 edges[i] = [ui, vi, wi] 表示一条从节点 ui 到 vi 的有向边,边的权值为 wi。
51+
同时给你两个整数 k 和 t。
52+
你的任务是确定在图中边权和 尽可能大的 路径,该路径需满足以下两个条件:
53+
- 路径包含 恰好 k 条边;
54+
- 路径上的边权值之和 严格小于 t。
55+
返回满足条件的一个路径的 最大 边权和。如果不存在这样的路径,则返回 -1。
56+
提示:
57+
1 <= n <= 300
58+
0 <= edges.length <= 300
59+
edges[i] = [ui, vi, wi]
60+
0 <= ui, vi < n
61+
ui != vi
62+
1 <= wi <= 10
63+
0 <= k <= 300
64+
1 <= t <= 600
65+
输入图是 有向无环图(DAG)。
66+
不存在重复的边。
67+
68+
DFS
69+
https://leetcode.cn/problems/maximum-weighted-k-edge-path/solutions/3673824/liang-chong-fang-fa-dfs-tuo-bu-xu-dppyth-vnva/
70+
时间复杂度 O((n+m)kt)。其中 m 是 edges 的长度。
71+
相似题目: 3509. 最大化交错和为 K 的子序列乘积
72+
https://leetcode.cn/problems/maximum-product-of-subsequences-with-an-alternating-sum-equal-to-k/description/
73+
rating 2092 (clist.by)
74+
*/
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.List;
4+
5+
public class Solution3544 {
6+
private List<Integer>[] g;
7+
private int[] nums;
8+
private int k;
9+
private long[][][] memo;
10+
11+
public long subtreeInversionSum(int[][] edges, int[] nums, int k) {
12+
int n = nums.length;
13+
this.nums = nums;
14+
this.k = k;
15+
g = new ArrayList[n];
16+
Arrays.setAll(g, e -> new ArrayList<>());
17+
for (int[] e : edges) {
18+
g[e[0]].add(e[1]);
19+
g[e[1]].add(e[0]);
20+
}
21+
memo = new long[n][k + 1][2];
22+
for (int i = 0; i < n; i++) {
23+
for (int j = 0; j < k + 1; j++) {
24+
memo[i][j][0] = Long.MIN_VALUE;
25+
memo[i][j][1] = Long.MAX_VALUE;
26+
}
27+
}
28+
return dfs(0, -1, k)[0];
29+
}
30+
31+
private long[] dfs(int x, int fa, int d) {
32+
long mx = nums[x], mn = nums[x];
33+
if (memo[x][d][0] != Long.MIN_VALUE) return memo[x][d];
34+
for (Integer y : g[x]) {
35+
if (y == fa) continue;
36+
long[] sub = dfs(y, x, Math.min(d + 1, k));
37+
mx += sub[0];
38+
mn += sub[1];
39+
}
40+
if (d >= k) {
41+
long mx2 = -nums[x], mn2 = -nums[x];
42+
for (Integer y : g[x]) {
43+
if (y == fa) continue;
44+
long[] sub = dfs(y, x, 1);
45+
mx2 -= sub[1];
46+
mn2 -= sub[0];
47+
}
48+
mx = Math.max(mx, mx2);
49+
mn = Math.min(mn, mn2);
50+
}
51+
return memo[x][d] = new long[]{mx, mn};
52+
}
53+
}
54+
/*
55+
3544. 子树反转和
56+
https://leetcode.cn/problems/subtree-inversion-sum/description/
57+
58+
第 156 场双周赛 T4。
59+
60+
给你一棵以节点 0 为根节点包含 n 个节点的无向树,节点编号从 0 到 n - 1。该树由长度为 n - 1 的二维整数数组 edges 表示,其中 edges[i] = [ui, vi] 表示节点 ui 和 vi 之间有一条边。
61+
同时给你一个整数 k 和长度为 n 的整数数组 nums,其中 nums[i] 表示节点 i 的值。
62+
你可以对部分节点执行 反转操作 ,该操作需满足以下条件:
63+
- 子树反转操作:
64+
- 当你反转一个节点时,以该节点为根的子树中所有节点的值都乘以 -1。
65+
- 反转之间的距离限制:
66+
- 你只能在一个节点与其他已反转节点“足够远”的情况下反转它。
67+
- 具体而言,如果你反转两个节点 a 和 b,并且其中一个是另一个的祖先(即 LCA(a, b) = a 或 LCA(a, b) = b),那么它们之间的距离(它们之间路径上的边数)必须至少为 k。
68+
返回应用 反转操作 后树上节点值的 最大可能 总和 。
69+
在一棵有根树中,某个节点 v 的子树是指所有路径到根节点包含 v 的节点集合。
70+
提示:
71+
2 <= n <= 5 * 10^4
72+
edges.length == n - 1
73+
edges[i] = [ui, vi]
74+
0 <= ui, vi < n
75+
nums.length == n
76+
-5 * 10^4 <= nums[i] <= 5 * 10^4
77+
1 <= k <= 50
78+
输入保证 edges 表示的是一棵合法的树。
79+
80+
树形 DP
81+
时间复杂度 O(nk)。
82+
有 O(n) 的做法。
83+
rating 2551 (clist.by)
84+
*/
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import java.util.Arrays;
2+
3+
public class Solution3545 {
4+
public int minDeletion(String s, int k) {
5+
int[] cnt = new int[26];
6+
for (char c : s.toCharArray()) {
7+
cnt[c - 'a']++;
8+
}
9+
Arrays.sort(cnt);
10+
11+
int ans = s.length();
12+
for (int i = 0; i < k; i++) {
13+
int j = 25 - i;
14+
ans -= cnt[j];
15+
}
16+
return ans;
17+
}
18+
}
19+
/*
20+
3545. 不同字符数量最多为 K 时的最少删除数
21+
https://leetcode.cn/problems/minimum-deletions-for-at-most-k-distinct-characters/description/
22+
23+
第 449 场周赛 T1。
24+
25+
给你一个字符串 s(由小写英文字母组成)和一个整数 k。
26+
你的任务是删除字符串中的一些字符(可以不删除任何字符),使得结果字符串中的 不同字符数量 最多为 k。
27+
返回为达到上述目标所需删除的 最小 字符数量。
28+
提示:
29+
1 <= s.length <= 16
30+
1 <= k <= 16
31+
s 仅由小写英文字母组成。
32+
33+
贪心。
34+
时间复杂度 O(ClogC)。其中 C = 26。
35+
*/
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
public class Solution3546 {
2+
private long[][] ps2d;
3+
4+
public boolean canPartitionGrid(int[][] grid) {
5+
int m = grid.length;
6+
int n = grid[0].length;
7+
8+
ps2d = new long[m + 1][n + 1];
9+
for (int i = 1; i <= m; i++) {
10+
for (int j = 1; j <= n; j++) {
11+
ps2d[i][j] = ps2d[i - 1][j] + ps2d[i][j - 1] - ps2d[i - 1][j - 1] + grid[i - 1][j - 1];
12+
}
13+
}
14+
if (ps2d[m][n] % 2 != 0) return false;
15+
long target = ps2d[m][n] / 2;
16+
17+
for (int i = 0; i < m; i++) {
18+
if (sumRegion(0, 0, i, n - 1) == target) return true;
19+
}
20+
for (int j = 0; j < n; j++) {
21+
if (sumRegion(0, 0, m - 1, j) == target) return true;
22+
}
23+
return false;
24+
}
25+
26+
// 求 [r1,c1] 到 [r2,c2] 的累加和
27+
private long sumRegion(int r1, int c1, int r2, int c2) {
28+
return ps2d[r2 + 1][c2 + 1] - ps2d[r2 + 1][c1] - ps2d[r1][c2 + 1] + ps2d[r1][c1];
29+
}
30+
}
31+
/*
32+
3546. 等和矩阵分割 I
33+
https://leetcode.cn/problems/equal-sum-grid-partition-i/description/
34+
35+
第 449 场周赛 T2。
36+
37+
给你一个由正整数组成的 m x n 矩阵 grid。你的任务是判断是否可以通过 一条水平或一条垂直分割线 将矩阵分割成两部分,使得:
38+
- 分割后形成的每个部分都是 非空 的。
39+
- 两个部分中所有元素的和 相等 。
40+
如果存在这样的分割,返回 true;否则,返回 false。
41+
提示:
42+
1 <= m == grid.length <= 10^5
43+
1 <= n == grid[i].length <= 10^5
44+
2 <= m * n <= 10^5
45+
1 <= grid[i][j] <= 10^5
46+
47+
二维前缀和 + 枚举。
48+
时间复杂度 O(mn)。
49+
相似题目: 3548. 等和矩阵分割 II
50+
https://leetcode.cn/problems/equal-sum-grid-partition-ii/description/
51+
*/

0 commit comments

Comments
 (0)