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 699db72

Browse files
committed
第153场双周赛T1~T4 & 第443场周赛T1~T4 (8)
1 parent 9457a6e commit 699db72

19 files changed

+963
-0
lines changed

‎jacoco-aggregate-report/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,11 @@
331331
<artifactId>leetcode-35</artifactId>
332332
<version>1.0-SNAPSHOT</version>
333333
</dependency>
334+
<dependency>
335+
<groupId>com.devyy</groupId>
336+
<artifactId>leetcode-36</artifactId>
337+
<version>1.0-SNAPSHOT</version>
338+
</dependency>
334339

335340

336341
<dependency>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
public class Solution3498 {
2+
public int reverseDegree(String s) {
3+
int n = s.length();
4+
int ans = 0;
5+
for (int i = 0; i < n; i++) {
6+
int pos = i + 1;
7+
int reverse_degree = 26 - (s.charAt(i) - 'a');
8+
ans += reverse_degree * pos;
9+
}
10+
return ans;
11+
}
12+
}
13+
/*
14+
3498. 字符串的反转度
15+
https://leetcode.cn/problems/reverse-degree-of-a-string/description/
16+
17+
第 153 场双周赛 T1。
18+
19+
给你一个字符串 s,计算其 反转度。
20+
反转度的计算方法如下:
21+
1.对于每个字符,将其在 反转 字母表中的位置('a' = 26, 'b' = 25, ..., 'z' = 1)与其在字符串中的位置(下标从1 开始)相乘。
22+
2.将这些乘积加起来,得到字符串中所有字符的和。
23+
返回 反转度。
24+
提示:
25+
1 <= s.length <= 1000
26+
s 仅包含小写字母。
27+
28+
模拟。
29+
时间复杂度 O(n)。
30+
*/
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
public class Solution3499 {
2+
// T2
3+
public int maxActiveSectionsAfterTrade(String S) {
4+
char[] s = S.toCharArray();
5+
int n = s.length;
6+
int cnt1 = 0;
7+
for (char c : s) {
8+
if (c == '1') cnt1++;
9+
}
10+
11+
int pre_0_len = -1;
12+
int ans = 0;
13+
int i = 0;
14+
while (i < n) {
15+
int st = i;
16+
for (i++; i < n && s[i] == s[st]; i++) {
17+
}
18+
if (s[st] == '0') {
19+
if (pre_0_len != -1) {
20+
ans = Math.max(ans, pre_0_len + (i - st));
21+
}
22+
pre_0_len = i - st;
23+
}
24+
}
25+
return ans + cnt1;
26+
}
27+
}
28+
/*
29+
3499. 操作后最大活跃区段数 I
30+
https://leetcode.cn/problems/maximize-active-section-with-trade-i/description/
31+
32+
第 153 场双周赛 T2。
33+
34+
给你一个长度为 n 的二进制字符串 s,其中:
35+
- '1' 表示一个 活跃 区段。
36+
- '0' 表示一个 非活跃 区段。
37+
你可以执行 最多一次操作 来最大化 s 中的活跃区段数量。在一次操作中,你可以:
38+
- 将一个被 '0' 包围的连续 '1' 区块转换为全 '0'。
39+
- 然后,将一个被 '1' 包围的连续 '0' 区块转换为全 '1'。
40+
返回在执行最优操作后,s 中的 最大 活跃区段数。
41+
注意:处理时需要在 s 的两侧加上 '1' ,即 t = '1' + s + '1'。这些加上的 '1' 不会影响最终的计数。
42+
提示:
43+
1 <= n == s.length <= 10^5
44+
s[i] 仅包含 '0' 或 '1'
45+
46+
分组循环。
47+
求最长 0-1-0 段的 0 数量 + 1 的数量。
48+
时间复杂度 O(n)。
49+
*/
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
public class Solution3500 {
2+
// O(n)
3+
public long minimumCost(int[] nums, int[] cost, int k) {
4+
int n = nums.length;
5+
long[] sumNums = new long[n + 1];
6+
long[] sumCost = new long[n + 1];
7+
for (int i = 0; i < n; i++) { // nums 和 cost 的前缀和
8+
sumNums[i + 1] = sumNums[i] + nums[i];
9+
sumCost[i + 1] = sumCost[i] + cost[i];
10+
}
11+
12+
long[] f = new long[n + 1];
13+
for (int i = 1; i <= n; i++) { // 注意这里 i 从 1 开始,下面不用把 i 加一
14+
f[i] = Long.MAX_VALUE;
15+
for (int j = 0; j < i; j++) {
16+
f[i] = Math.min(f[i], f[j] + sumNums[i] * (sumCost[i] - sumCost[j]) + k * (sumCost[n] - sumCost[j]));
17+
}
18+
}
19+
return f[n];
20+
}
21+
}
22+
/*
23+
3500. 将数组分割为子数组的最小代价
24+
https://leetcode.cn/problems/minimum-cost-to-divide-array-into-subarrays/description/
25+
26+
第 153 场双周赛 T3。
27+
28+
给你两个长度相等的整数数组 nums 和 cost,和一个整数 k。
29+
你可以将 nums 分割成多个子数组。第 i 个子数组由元素 nums[l..r] 组成,其代价为:
30+
- (nums[0] + nums[1] + ... + nums[r] + k * i) * (cost[l] + cost[l + 1] + ... + cost[r])。
31+
注意,i 表示子数组的顺序:第一个子数组为 1,第二个为 2,依此类推。
32+
返回通过任何有效划分得到的 最小 总代价。
33+
子数组 是一个连续的 非空 元素序列。
34+
提示:
35+
1 <= nums.length <= 1000
36+
cost.length == nums.length
37+
1 <= nums[i], cost[i] <= 1000
38+
1 <= k <= 1000
39+
40+
Abel 求和 + 划分型 DP / O(n) 斜率优化
41+
https://leetcode.cn/problems/minimum-cost-to-divide-array-into-subarrays/solutions/3633352/hua-fen-xing-dp-shi-zi-bian-xing-pythonj-cwi9/
42+
前缀和 & DP
43+
https://leetcode.cn/problems/minimum-cost-to-divide-array-into-subarrays/solutions/3633239/qian-zhui-he-dp-by-tsreaper-7g2c/
44+
没做出来的读者不用灰心,因为如果之前没有接触过倍率转为前(后)缀和的套路,一般很难想到这个转化。
45+
rating 2563 (clist.by)
46+
*/
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 Solution3498Tests {
5+
private final Solution3498 solution3498 = new Solution3498();
6+
7+
@Test
8+
public void example1() {
9+
String s = "abc";
10+
int expected = 148;
11+
Assertions.assertEquals(expected, solution3498.reverseDegree(s));
12+
}
13+
14+
@Test
15+
public void example2() {
16+
String s = "zaza";
17+
int expected = 160;
18+
Assertions.assertEquals(expected, solution3498.reverseDegree(s));
19+
}
20+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3499Tests {
5+
private final Solution3499 solution3499 = new Solution3499();
6+
7+
@Test
8+
public void example1() {
9+
String s = "01";
10+
int expected = 1;
11+
Assertions.assertEquals(expected, solution3499.maxActiveSectionsAfterTrade(s));
12+
}
13+
14+
@Test
15+
public void example2() {
16+
String s = "0100";
17+
int expected = 4;
18+
Assertions.assertEquals(expected, solution3499.maxActiveSectionsAfterTrade(s));
19+
}
20+
21+
@Test
22+
public void example3() {
23+
String s = "1000100";
24+
int expected = 7;
25+
Assertions.assertEquals(expected, solution3499.maxActiveSectionsAfterTrade(s));
26+
}
27+
28+
@Test
29+
public void example4() {
30+
String s = "01010";
31+
int expected = 4;
32+
Assertions.assertEquals(expected, solution3499.maxActiveSectionsAfterTrade(s));
33+
}
34+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3500Tests {
5+
private final Solution3500 solution3500 = new Solution3500();
6+
7+
@Test
8+
public void example1() {
9+
int[] nums = {3, 1, 4};
10+
int[] cost = {4, 6, 6};
11+
int k = 1;
12+
long expected = 110;
13+
Assertions.assertEquals(expected, solution3500.minimumCost(nums, cost, k));
14+
}
15+
16+
@Test
17+
public void example2() {
18+
int[] nums = {4, 8, 5, 1, 14, 2, 2, 12, 1};
19+
int[] cost = {7, 2, 8, 4, 2, 2, 1, 1, 2};
20+
int k = 7;
21+
long expected = 985;
22+
Assertions.assertEquals(expected, solution3500.minimumCost(nums, cost, k));
23+
}
24+
}

‎leetcode/leetcode-36/pom.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>com.devyy</groupId>
8+
<artifactId>leetcode</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>leetcode-36</artifactId>
13+
14+
<properties>
15+
<maven.compiler.source>21</maven.compiler.source>
16+
<maven.compiler.target>21</maven.compiler.target>
17+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18+
</properties>
19+
20+
<dependencies>
21+
<dependency>
22+
<groupId>com.devyy</groupId>
23+
<artifactId>leetcode-core</artifactId>
24+
<version>1.0-SNAPSHOT</version>
25+
</dependency>
26+
</dependencies>
27+
</project>
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import java.util.ArrayList;
2+
import java.util.List;
3+
import java.util.function.Function;
4+
5+
public class Solution3501 {
6+
private record Pair(int l, int r) { // 左闭右开
7+
}
8+
9+
private static class SparseTable {
10+
private final int[][] st;
11+
12+
SparseTable(List<Pair> a) {
13+
int n = a.size() - 1;
14+
int sz = 32 - Integer.numberOfLeadingZeros(n);
15+
st = new int[n][sz];
16+
for (int i = 0; i < n; i++) {
17+
st[i][0] = a.get(i).r - a.get(i).l + a.get(i + 1).r - a.get(i + 1).l;
18+
}
19+
for (int j = 1; j < sz; j++) {
20+
for (int i = 0; i + (1 << j) <= n; i++) {
21+
st[i][j] = Math.max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
22+
}
23+
}
24+
}
25+
26+
// 查询区间最大值,[l,r) 左闭右开
27+
int query(int l, int r) {
28+
if (l >= r) {
29+
return 0;
30+
}
31+
int k = 32 - Integer.numberOfLeadingZeros(r - l) - 1;
32+
return Math.max(st[l][k], st[r - (1 << k)][k]);
33+
}
34+
}
35+
36+
public List<Integer> maxActiveSectionsAfterTrade(String S, int[][] queries) {
37+
char[] s = S.toCharArray();
38+
int n = s.length;
39+
int total1 = 0;
40+
List<Pair> a = new ArrayList<>();
41+
a.add(new Pair(-1, -1)); // 哨兵
42+
int start = 0;
43+
for (int i = 0; i < n; i++) {
44+
if (i == n - 1 || s[i] != s[i + 1]) {
45+
if (s[i] == '1') {
46+
total1 += i - start + 1;
47+
} else {
48+
a.add(new Pair(start, i + 1)); // 左闭右开
49+
}
50+
start = i + 1;
51+
}
52+
}
53+
a.add(new Pair(n + 1, n + 1)); // 哨兵
54+
55+
SparseTable st = new SparseTable(a);
56+
List<Integer> ans = new ArrayList<>(queries.length);
57+
for (int[] query : queries) {
58+
int ql = query[0];
59+
int qr = query[1] + 1; // 左闭右开
60+
61+
// 找第一个区间,左端点 >= ql
62+
// 找最后一个区间,右端点 <= qr
63+
// a 中没有重复的区间左右端点,可以直接用库函数二分
64+
// int i = Collections.binarySearch(a, new Pair(ql, 0), (p, q) -> p.l - q.l);
65+
// if (i < 0) i = ~i;
66+
// int j = Collections.binarySearch(a, new Pair(0, qr + 1), (p, q) -> p.r - q.r);
67+
// if (j < 0) j = ~j;
68+
// j--;
69+
int i = sortSearch(a.size(), m -> a.get(m).l >= ql);
70+
int j = sortSearch(a.size(), m -> a.get(m).r >= qr + 1) - 1;
71+
72+
int mx = 0;
73+
if (i <= j) { // [ql,qr) 中有完整的区间
74+
int full = st.query(i, j); // 相邻完整区间的长度之和的最大值
75+
int sl = merge(a.get(i - 1).r - ql, a.get(i).r - a.get(i).l); // 残缺区间 i-1 + 完整区间 i
76+
int sr = merge(qr - a.get(j + 1).l, a.get(j).r - a.get(j).l); // 残缺区间 j+1 + 完整区间 j
77+
mx = Math.max(full, Math.max(sl, sr));
78+
} else if (i == j + 1) { // [ql,qr) 中有两个相邻的残缺区间
79+
mx = merge(a.get(i - 1).r - ql, qr - a.get(j + 1).l); // 残缺区间 i-1 + 残缺区间 j+1
80+
}
81+
ans.add(total1 + mx);
82+
}
83+
return ans;
84+
}
85+
86+
private int sortSearch(int n, Function<Integer, Boolean> f) {
87+
int l = 0, r = n;
88+
while (l < r) {
89+
int mid = l + (r - l) / 2;
90+
if (f.apply(mid)) r = mid;
91+
else l = mid + 1;
92+
}
93+
return l;
94+
}
95+
96+
private int merge(int x, int y) {
97+
return x > 0 && y > 0 ? x + y : 0;
98+
}
99+
}
100+
/*
101+
3501. 操作后最大活跃区段数 II
102+
https://leetcode.cn/problems/maximize-active-section-with-trade-ii/description/
103+
104+
第 153 场双周赛 T4。
105+
106+
给你一个长度为 n 的二进制字符串 s ,其中:
107+
- '1' 表示一个 活跃 区域。
108+
- '0' 表示一个 非活跃 区域。
109+
你最多可以进行一次 操作 来最大化 s 中活跃区间的数量。在一次操作中,你可以:
110+
将一个被 '0' 包围的连续 '1' 区域转换为全 '0'。
111+
然后,将一个被 '1' 包围的连续 '0' 区域转换为全 '1'。
112+
此外,你还有一个 二维数组 queries,其中 queries[i] = [li, ri] 表示子字符串 s[li...ri]。
113+
对于每个查询,确定在对子字符串 s[li...ri] 进行最优交换后,字符串 s 中 可能的最大 活跃区间数。
114+
返回一个数组 answer,其中 answer[i] 是 queries[i] 的结果。
115+
注意
116+
对于每个查询,仅对 s[li...ri] 处理时,将其看作是在两端都加上一个 '1' 后的字符串,形成 t = '1' + s[li...ri] + '1'。这些额外的 '1' 不会对最终的活跃区间数有贡献。
117+
各个查询相互独立。
118+
提示:
119+
1 <= n == s.length <= 10^5
120+
1 <= queries.length <= 10^5
121+
s[i] 只有 '0' 或 '1'。
122+
queries[i] = [li, ri]
123+
0 <= li <= ri < n
124+
125+
区间最大值 + 分类讨论
126+
时间复杂度 O(nlogn + qlogn)。
127+
rating 3025 (clist.by)
128+
*/

0 commit comments

Comments
(0)

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