Skip to content

Commit 0d8ee85

Browse files
committed
第149场双周赛T1~T4 & 第435场周赛T1~T4 (8)
1 parent 3ea9d82 commit 0d8ee85

16 files changed

+661
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
public class Solution3438 {
2+
public String findValidPair(String S) {
3+
char[] s = S.toCharArray();
4+
int[] cnt = new int[10];
5+
for (char c : s) {
6+
cnt[c - '0']++;
7+
}
8+
for (int i = 1; i < s.length; i++) {
9+
if (s[i - 1] == s[i]) continue;
10+
if (cnt[s[i - 1] - '0'] == s[i - 1] - '0' &&
11+
cnt[s[i] - '0'] == s[i] - '0') {
12+
return S.substring(i - 1, i + 1);
13+
}
14+
}
15+
return "";
16+
}
17+
}
18+
/*
19+
3438. 找到字符串中合法的相邻数字
20+
https://leetcode.cn/problems/find-valid-pair-of-adjacent-digits-in-string/description/
21+
22+
第 149 场双周赛 T1。
23+
24+
给你一个只包含数字的字符串 s 。如果 s 中两个 相邻 的数字满足以下条件,我们称它们是 合法的 :
25+
- 前面的数字 不等于 第二个数字。
26+
- 两个数字在 s 中出现的次数 恰好 分别等于这个数字本身。
27+
请你从左到右遍历字符串 s ,并返回最先找到的 合法 相邻数字。如果这样的相邻数字不存在,请你返回一个空字符串。
28+
提示:
29+
2 <= s.length <= 100
30+
s 只包含 '1' 到 '9' 的数字。
31+
32+
中国时间:2025-02-01 22:30
33+
2025春节初四
34+
模拟。
35+
*/
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
public class Solution3439 {
2+
private int eventTime;
3+
private int[] startTime, endTime;
4+
5+
public int maxFreeTime(int eventTime, int k, int[] startTime, int[] endTime) {
6+
this.eventTime = eventTime;
7+
this.startTime = startTime;
8+
this.endTime = endTime;
9+
10+
int n = startTime.length;
11+
int s = 0;
12+
for (int i = 0; i < k; i++) {
13+
s += get(i);
14+
}
15+
int ans = s;
16+
for (int i = k; i <= n; i++) {
17+
s += get(i);
18+
ans = Math.max(ans, s);
19+
s -= get(i - k);
20+
}
21+
return ans;
22+
}
23+
24+
private int get(int i) {
25+
if (i == 0) {
26+
return startTime[0];
27+
}
28+
int n = startTime.length;
29+
if (i == n) {
30+
return eventTime - endTime[n - 1];
31+
}
32+
return startTime[i] - endTime[i - 1];
33+
}
34+
}
35+
/*
36+
3439. 重新安排会议得到最多空余时间 I
37+
https://leetcode.cn/problems/reschedule-meetings-for-maximum-free-time-i/description/
38+
39+
第 149 场双周赛 T2。
40+
41+
给你一个整数 eventTime 表示一个活动的总时长,这个活动开始于 t = 0 ,结束于 t = eventTime 。
42+
同时给你两个长度为 n 的整数数组 startTime 和 endTime 。它们表示这次活动中 n 个时间 没有重叠 的会议,其中第 i 个会议的时间为 [startTime[i], endTime[i]] 。
43+
你可以重新安排 至多 k 个会议,安排的规则是将会议时间平移,且保持原来的 会议时长 ,你的目的是移动会议后 最大化 相邻两个会议之间的 最长 连续空余时间。
44+
移动前后所有会议之间的 相对 顺序需要保持不变,而且会议时间也需要保持互不重叠。
45+
请你返回重新安排会议以后,可以得到的 最大 空余时间。
46+
注意,会议 不能 安排到整个活动的时间以外。
47+
提示:
48+
1 <= eventTime <= 10^9
49+
n == startTime.length == endTime.length
50+
2 <= n <= 10^5
51+
1 <= k <= n
52+
0 <= startTime[i] < endTime[i] <= eventTime
53+
endTime[i] <= startTime[i + 1] 其中 i 在范围 [0, n - 2] 之间。
54+
55+
定长滑动窗口。
56+
问题等价于:给你 n+1 个空余时间段,合并其中 k+1 个连续的空余时间段,得到的最大长度是多少?
57+
时间复杂度 O(n)。
58+
相似题目: 3440. 重新安排会议得到最多空余时间 II
59+
https://leetcode.cn/problems/reschedule-meetings-for-maximum-free-time-ii/description/
60+
*/
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
public class Solution3440 {
2+
private int eventTime;
3+
private int[] startTime, endTime;
4+
5+
public int maxFreeTime(int eventTime, int[] startTime, int[] endTime) {
6+
this.eventTime = eventTime;
7+
this.startTime = startTime;
8+
this.endTime = endTime;
9+
10+
int n = startTime.length;
11+
// 最大的三个空位所在的位置(下标)分别是 a,b,c。
12+
int a = 0, b = -1, c = -1;
13+
for (int i = 1; i <= n; i++) {
14+
int sz = get(i);
15+
if (sz > get(a)) {
16+
c = b;
17+
b = a;
18+
a = i;
19+
} else if (b < 0 || sz > get(b)) {
20+
c = b;
21+
b = i;
22+
} else if (c < 0 || sz > get(c)) {
23+
c = i;
24+
}
25+
}
26+
27+
int ans = 0;
28+
for (int i = 0; i < n; i++) {
29+
int sz = endTime[i] - startTime[i];
30+
if (i != a && i + 1 != a && sz <= get(a) ||
31+
i != b && i + 1 != b && sz <= get(b) ||
32+
sz <= get(c)) {
33+
ans = Math.max(ans, get(i) + sz + get(i + 1));
34+
} else {
35+
ans = Math.max(ans, get(i) + get(i + 1));
36+
}
37+
}
38+
return ans;
39+
}
40+
41+
private int get(int i) {
42+
if (i == 0) {
43+
return startTime[0];
44+
}
45+
int n = startTime.length;
46+
if (i == n) {
47+
return eventTime - endTime[n - 1];
48+
}
49+
return startTime[i] - endTime[i - 1];
50+
}
51+
}
52+
/*
53+
3440. 重新安排会议得到最多空余时间 II
54+
https://leetcode.cn/problems/reschedule-meetings-for-maximum-free-time-ii/description/
55+
56+
第 149 场双周赛 T3。
57+
58+
给你一个整数 eventTime 表示一个活动的总时长,这个活动开始于 t = 0 ,结束于 t = eventTime 。
59+
同时给你两个长度为 n 的整数数组 startTime 和 endTime 。它们表示这次活动中 n 个时间 没有重叠 的会议,其中第 i 个会议的时间为 [startTime[i], endTime[i]] 。
60+
你可以重新安排 至多 一个会议,安排的规则是将会议时间平移,且保持原来的 会议时长 ,你的目的是移动会议后 最大化 相邻两个会议之间的 最长 连续空余时间。
61+
请你返回重新安排会议以后,可以得到的 最大 空余时间。
62+
注意,会议 不能 安排到整个活动的时间以外,且会议之间需要保持互不重叠。
63+
注意:重新安排会议以后,会议之间的顺序可以发生改变。
64+
提示:
65+
1 <= eventTime <= 10^9
66+
n == startTime.length == endTime.length
67+
2 <= n <= 10^5
68+
0 <= startTime[i] < endTime[i] <= eventTime
69+
endTime[i] <= startTime[i + 1] 其中 i 在范围 [0, n - 2] 之间。
70+
71+
维护前三大的空位+枚举+分类讨论。
72+
时间复杂度 O(n)。
73+
相似题目: 3439. 重新安排会议得到最多空余时间 I
74+
https://leetcode.cn/problems/reschedule-meetings-for-maximum-free-time-i/description/
75+
*/
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
public class Solution3441 {
2+
public String minCostGoodCaption(String caption) {
3+
int n = caption.length();
4+
if (n < 3) {
5+
return "";
6+
}
7+
8+
char[] s = caption.toCharArray();
9+
int[][] f = new int[n + 1][26];
10+
int[] minJ = new int[n + 1];
11+
int[][] nxt = new int[n + 1][26];
12+
for (int i = n - 1; i >= 0; i--) {
13+
int mn = Integer.MAX_VALUE;
14+
for (int j = 0; j < 26; j++) {
15+
int res = f[i + 1][j] + Math.abs(s[i] - 'a' - j);
16+
int res2 = i <= n - 6 ? f[i + 3][minJ[i + 3]] + Math.abs(s[i] - 'a' - j) + Math.abs(s[i + 1] - 'a' - j) + Math.abs(s[i + 2] - 'a' - j) : Integer.MAX_VALUE;
17+
if (res2 < res || res2 == res && minJ[i + 3] < j) {
18+
res = res2;
19+
nxt[i][j] = minJ[i + 3]; // 记录转移来源
20+
} else {
21+
nxt[i][j] = j; // 记录转移来源
22+
}
23+
f[i][j] = res;
24+
if (res < mn) {
25+
mn = res;
26+
minJ[i] = j; // 记录最小的 f[i][j] 中的 j 是多少
27+
}
28+
}
29+
}
30+
31+
char[] ans = new char[n];
32+
int i = 0;
33+
int j = minJ[0];
34+
while (i < n) {
35+
ans[i] = (char) ('a' + j);
36+
int k = nxt[i][j];
37+
if (k == j) {
38+
i++;
39+
} else {
40+
ans[i + 2] = ans[i + 1] = ans[i];
41+
i += 3;
42+
j = k;
43+
}
44+
}
45+
return new String(ans);
46+
}
47+
48+
}
49+
/*
50+
3441. 变成好标题的最少代价
51+
https://leetcode.cn/problems/minimum-cost-good-caption/description/
52+
53+
第 149 场双周赛 T4。
54+
55+
给你一个长度为 n 的字符串 caption 。如果字符串中 每一个 字符都位于连续出现 至少 3 次 的组中,那么我们称这个字符串是 好 标题。
56+
比方说:
57+
- "aaabbb" 和 "aaaaccc" 都是 好 标题。
58+
- "aabbb" 和 "ccccd" 都 不是 好标题。
59+
你可以对字符串执行以下操作 任意 次:
60+
选择一个下标 i(其中 0 <= i < n )然后将该下标处的字符变为:
61+
- 该字符在字母表中 前 一个字母(前提是 caption[i] != 'a' )
62+
- 该字符在字母表中 后 一个字母(caption[i] != 'z' )
63+
你的任务是用 最少 操作次数将 caption 变为 好 标题。如果存在 多种 好标题,请返回它们中 字典序最小 的一个。如果 无法 得到好标题,请你返回一个空字符串 "" 。
64+
在字符串 a 和 b 中,如果两个字符串第一个不同的字符处,字符串 a 的字母比 b 的字母在字母表里出现的顺序更早,那么我们称字符串 a 的 字典序 比 b 小 。如果两个字符串前 min(a.length, b.length) 个字符都相同,那么较短的一个字符串字典序比另一个字符串小。
65+
提示:
66+
1 <= caption.length <= 5 * 10^4
67+
caption 只包含小写英文字母。
68+
69+
枚举字母+DP。
70+
https://leetcode.cn/problems/minimum-cost-good-caption/solutions/3061609/zhuang-tai-ji-dp-shu-chu-ju-ti-fang-an-p-kjry/
71+
rating 2780 (clist.by)
72+
*/
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
public class Solution3442 {
2+
public int maxDifference(String s) {
3+
int[] cnt = new int[26];
4+
for (char c : s.toCharArray()) {
5+
cnt[c - 'a']++;
6+
}
7+
8+
int maxOdd = 0, minEven = Integer.MAX_VALUE;
9+
for (int c : cnt) {
10+
if (c % 2 == 1) maxOdd = Math.max(maxOdd, c);
11+
else if (c > 0) minEven = Math.min(minEven, c);
12+
}
13+
return maxOdd - minEven;
14+
}
15+
}
16+
/*
17+
3442. 奇偶频次间的最大差值 I
18+
https://leetcode.cn/problems/maximum-difference-between-even-and-odd-frequency-i/description/
19+
20+
第 435 场周赛 T1。
21+
22+
给你一个由小写英文字母组成的字符串 s 。请你找出字符串中两个字符的出现频次之间的 最大 差值,这两个字符需要满足:
23+
- 一个字符在字符串中出现 偶数次 。
24+
- 另一个字符在字符串中出现 奇数次 。
25+
返回 最大 差值,计算方法是出现 奇数次 字符的次数 减去 出现 偶数次 字符的次数。
26+
提示:
27+
3 <= s.length <= 100
28+
s 仅由小写英文字母组成。
29+
s 至少由一个出现奇数次的字符和一个出现偶数次的字符组成。
30+
31+
中国时间:2025-02-02 10:30
32+
2025春节初五
33+
统计频次。
34+
*/
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
public class Solution3443 {
2+
public int maxDistance(String s, int k) {
3+
int x = 0, y = 0;
4+
int ans = 0;
5+
for (int i = 0; i < s.length(); i++) {
6+
char c = s.charAt(i);
7+
if (c == 'N') y++;
8+
else if (c == 'S') y--;
9+
else if (c == 'E') x++;
10+
else x--;
11+
ans = Math.max(ans, Math.min(Math.abs(x) + Math.abs(y) + k * 2, i + 1));
12+
}
13+
return ans;
14+
}
15+
}
16+
/*
17+
3443. K 次修改后的最大曼哈顿距离
18+
https://leetcode.cn/problems/maximum-manhattan-distance-after-k-changes/description/
19+
20+
第 435 场周赛 T2。
21+
22+
给你一个由字符 'N'、'S'、'E' 和 'W' 组成的字符串 s,其中 s[i] 表示在无限网格中的移动操作:
23+
- 'N':向北移动 1 个单位。
24+
- 'S':向南移动 1 个单位。
25+
- 'E':向东移动 1 个单位。
26+
- 'W':向西移动 1 个单位。
27+
初始时,你位于原点 (0, 0)。你 最多 可以修改 k 个字符为任意四个方向之一。
28+
请找出在 按顺序 执行所有移动操作过程中的 任意时刻 ,所能达到的离原点的 最大曼哈顿距离 。
29+
曼哈顿距离 定义为两个坐标点 (xi, yi) 和 (xj, yj) 的横向距离绝对值与纵向距离绝对值之和,即 |xi - xj| + |yi - yj|。
30+
提示:
31+
1 <= s.length <= 10^5
32+
0 <= k <= s.length
33+
s 仅由 'N'、'S'、'E' 和 'W' 。
34+
35+
每操作一次,曼哈顿距离都会增大 2,但这不会超过移动的次数 i+1。
36+
所以执行完 s[i] 后的答案为 min(|x|+|y|+2k,i+1)
37+
时间复杂度 O(n)。
38+
*/
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import java.util.Arrays;
2+
3+
public class Solution3444 {
4+
private static final long INF = (long) 1e18;
5+
private long[] lcms;
6+
private long[][] memo;
7+
8+
public int minimumIncrements(int[] nums, int[] target) {
9+
int n = nums.length;
10+
int m = target.length;
11+
12+
// 预处理 target 的所有子集的 LCM
13+
lcms = new long[1 << m];
14+
lcms[0] = 1;
15+
for (int i = 0; i < m; i++) {
16+
int bit = 1 << i;
17+
for (int mask = 0; mask < bit; mask++) {
18+
lcms[bit | mask] = getLCM(target[i], lcms[mask]);
19+
}
20+
}
21+
22+
memo = new long[n][1 << m];
23+
for (int i = 0; i < n; i++) {
24+
Arrays.fill(memo[i], -1);
25+
}
26+
return (int) dfs(n - 1, (1 << m) - 1, nums);
27+
}
28+
29+
private long dfs(int i, int j, int[] nums) {
30+
if (j == 0) return 0;
31+
if (i < 0) { // 不能有剩余元素
32+
return INF;
33+
}
34+
if (memo[i][j] != -1) return memo[i][j];
35+
long res = dfs(i - 1, j, nums); // 不修改 nums[i]
36+
for (int sub = j; sub > 0; sub = (sub - 1) & j) { // 枚举 j 的所有非空子集
37+
long l = lcms[sub];
38+
res = Math.min(res, dfs(i - 1, j ^ sub, nums) + (l - nums[i] % l) % l);
39+
}
40+
return memo[i][j] = res;
41+
}
42+
43+
private long getGCD(long num1, long num2) {
44+
return num1 == 0 ? num2 : getGCD(num2 % num1, num1);
45+
}
46+
47+
private long getLCM(long num1, long num2) {
48+
return num1 / getGCD(num1, num2) * num2;
49+
}
50+
}
51+
/*
52+
3444. 使数组包含目标值倍数的最少增量
53+
https://leetcode.cn/problems/minimum-increments-for-target-multiples-in-an-array/description/
54+
55+
第 435 场周赛 T3。
56+
57+
给你两个数组 nums 和 target 。
58+
在一次操作中,你可以将 nums 中的任意一个元素递增 1 。
59+
返回要使 target 中的每个元素在 nums 中 至少 存在一个倍数所需的 最少操作次数 。
60+
提示:
61+
1 <= nums.length <= 5 * 10^4
62+
1 <= target.length <= 4
63+
target.length <= nums.length
64+
1 <= nums[i], target[i] <= 10^4
65+
66+
子集状压 DP:记忆化搜索。
67+
rating 2346 (clist.by)
68+
*/

0 commit comments

Comments
 (0)