Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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)

AltStyle によって変換されたページ (->オリジナル) /