Skip to content

Commit 2d9604b

Browse files
Update
1 parent 717ad84 commit 2d9604b

20 files changed

+991
-232
lines changed

Diff for: README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@
107107
5. [数组:209.长度最小的子数组](./problems/0209.长度最小的子数组.md)
108108
6. [数组:区间和](./problems/kamacoder/0058.区间和.md)
109109
6. [数组:59.螺旋矩阵II](./problems/0059.螺旋矩阵II.md)
110-
7. [数组:总结篇](./problems/数组总结篇.md)
110+
7. [数组:区间和](./problems/kamacoder/0058.区间和.md)
111+
8. [数组:开发商购买土地](./problems/kamacoder/0044.开发商购买土地.md)
112+
9. [数组:总结篇](./problems/数组总结篇.md)
111113

112114
## 链表
113115

Diff for: problems/kamacoder/0044.开发商购买土地.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11

22
# 44. 开发商购买土地
33

4+
> 本题为代码随想录后续扩充题目,还没有视频讲解,顺便让大家练习一下ACM输入输出模式(笔试面试必备)
5+
6+
[题目链接](https://kamacoder.com/problempage.php?pid=1044)
7+
48
【题目描述】
59

610
在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。
@@ -57,7 +61,7 @@
5761

5862
如果本题要求 任何两个行(或者列)之间的数值总和,大家在[0058.区间和](./0058.区间和.md) 的基础上 应该知道怎么求。
5963

60-
就是前缀和的思路,先统计好,前n行的和 q[n],如果要求矩阵 a 行到 b行 之间的总和,那么就 q[b] - q[a - 1]就好。
64+
就是前缀和的思路,先统计好,前n行的和 q[n],如果要求矩阵 a行 到 b行 之间的总和,那么就 q[b] - q[a - 1]就好。
6165

6266
至于为什么是 a - 1,大家去看 [0058.区间和](./0058.区间和.md) 的分析,使用 前缀和 要注意 区间左右边的开闭情况。
6367

Diff for: problems/kamacoder/0058.区间和.md

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
# 58. 区间和
33

4+
> 本题为代码随想录后续扩充题目,还没有视频讲解,顺便让大家练习一下ACM输入输出模式(笔试面试必备)
5+
46
[题目链接](https://kamacoder.com/problempage.php?pid=1070)
57

68
题目描述
@@ -97,27 +99,29 @@ int main() {
9799

98100
为什么呢?
99101

100-
p[1] = vec[0] + vec[1];
102+
`p[1] = vec[0] + vec[1];`
101103

102-
p[5] = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5];
104+
`p[5] = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5];`
103105

104-
p[5] - p[1] = vec[2] + vec[3] + vec[4] + vec[5];
106+
`p[5] - p[1] = vec[2] + vec[3] + vec[4] + vec[5];`
105107

106108
这不就是我们要求的 下标 2 到下标 5 之间的累加和吗。
107109

108110
如图所示:
109111

110112
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240627111319.png)
111113

112-
p[5] - p[1] 就是 红色部分的区间和。
114+
`p[5] - p[1]` 就是 红色部分的区间和。
113115

114-
而 p 数组是我们之前就计算好的累加和,所以后面每次求区间和的之后 我们只需要 O(1)的操作。
116+
而 p 数组是我们之前就计算好的累加和,所以后面每次求区间和的之后 我们只需要 O(1) 的操作。
115117

116118
**特别注意**: 在使用前缀和求解的时候,要特别注意 求解区间。
117119

118120
如上图,如果我们要求 区间下标 [2, 5] 的区间和,那么应该是 p[5] - p[1],而不是 p[5] - p[2]
119121

120-
很多录友在使用前缀和的时候,分不清前缀和的区间,建议画一画图,模拟一下 思路会更清晰。
122+
**很多录友在使用前缀和的时候,分不清前缀和的区间,建议画一画图,模拟一下 思路会更清晰**
123+
124+
本题C++代码如下:
121125

122126
```CPP
123127
#include <iostream>

Diff for: problems/kamacoder/0098.所有可达路径.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,8 @@ int main() {
422422
## 其他语言版本
423423

424424
### Java
425-
#### 邻接矩阵写法
425+
426+
邻接矩阵写法
426427
```java
427428
import java.util.ArrayList;
428429
import java.util.List;
@@ -477,7 +478,7 @@ public class Main {
477478
}
478479
```
479480

480-
#### 邻接表写法
481+
邻接表写法
481482
```java
482483
import java.util.ArrayList;
483484
import java.util.LinkedList;
@@ -533,7 +534,7 @@ public class Main {
533534
}
534535
```
535536
### Python
536-
#### 邻接矩阵写法
537+
邻接矩阵写法
537538
``` python
538539
def dfs(graph, x, n, path, result):
539540
if x == n:
@@ -566,7 +567,7 @@ if __name__ == "__main__":
566567
main()
567568
```
568569

569-
#### 邻接表写法
570+
邻接表写法
570571
``` python
571572
from collections import defaultdict
572573

Diff for: problems/kamacoder/0109.冗余连接II.md

+1
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ int main() {
225225
vec.push_back(i);
226226
}
227227
}
228+
// 情况一、情况二
228229
if (vec.size() > 0) {
229230
// 放在vec里的边已经按照倒叙放的,所以这里就优先删vec[0]这条边
230231
if (isTreeAfterRemoveEdge(edges, vec[0])) {

Diff for: problems/kamacoder/0113.国际象棋.md

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
2+
# 113.国际象棋
3+
4+
广搜,但本题如果广搜枚举马和象的话会超时。
5+
6+
广搜要只枚举马的走位,同时判断是否在对角巷直接走象
7+
8+
```CPP
9+
#include <iostream>
10+
using namespace std;
11+
const int N = 100005, mod = 1000000007;
12+
using ll = long long;
13+
int n, ans;
14+
int dir[][2] = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, -1}, {-2, 1}};
15+
int main() {
16+
int x1, y1, x2, y2;
17+
cin >> n;
18+
while (n--) {
19+
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
20+
if (x1 == x2 && y1 == y2) {
21+
cout << 0 << endl;
22+
continue;
23+
}
24+
// 判断象走一步到达
25+
int d = abs(x1 - x2) - abs(y1 - y2);
26+
if (!d) {cout << 1 << endl; continue;}
27+
// 判断马走一步到达
28+
bool one = 0;
29+
for (int i = 0; i < 8; ++i) {
30+
int dx = x1 + dir[i][0], dy = y1 + dir[i][1];
31+
if (dx == x2 && dy == y2) {
32+
cout << 1 << endl;
33+
one = true;
34+
break;
35+
}
36+
}
37+
if (one) continue;
38+
// 接下来为两步的逻辑, 象走两步或者马走一步,象走一步
39+
// 象直接两步可以到达,这个计算是不是同颜色的格子,象可以在两步到达所有同颜色的格子
40+
int d2 = abs(x1 - x2) + abs(y1 - y2);
41+
if (d2 % 2 == 0) {
42+
cout << 2 << endl;
43+
continue;
44+
}
45+
// 接下来判断马 + 象的组合
46+
bool two = 0;
47+
for (int i = 0; i < 8; ++i) {
48+
int dx = x1 + dir[i][0], dy = y1 + dir[i][1];
49+
int d = abs(dx - x2) - abs(dy - y2);
50+
if (!d) {cout << 2 << endl; two = true; break;}
51+
}
52+
if (two) continue;
53+
// 剩下的格子全都是三步到达的
54+
cout << 3 << endl;
55+
}
56+
return 0;
57+
}
58+
59+
```

Diff for: problems/kamacoder/0121.小红的区间翻转.md

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
2+
# 121. 小红的区间翻转
3+
4+
比较暴力的方式,就是直接模拟, 枚举所有 区间,然后检查其翻转的情况。
5+
6+
在检查翻转的时候,需要一些代码优化,否则容易超时。
7+
8+
```CPP
9+
#include <iostream>
10+
#include <vector>
11+
using namespace std;
12+
13+
bool canTransform(const vector<int>& a, const vector<int>& b, int left, int right) {
14+
// 提前检查翻转区间的值是否可以匹配
15+
for (int i = left, j = right; i <= right; i++, j--) {
16+
if (a[i] != b[j]) {
17+
return false;
18+
}
19+
}
20+
// 检查翻转区间外的值是否匹配
21+
for (int i = 0; i < left; i++) {
22+
if (a[i] != b[i]) {
23+
return false;
24+
}
25+
}
26+
for (int i = right + 1; i < a.size(); i++) {
27+
if (a[i] != b[i]) {
28+
return false;
29+
}
30+
}
31+
return true;
32+
}
33+
34+
int main() {
35+
int n;
36+
cin >> n;
37+
38+
vector<int> a(n);
39+
vector<int> b(n);
40+
41+
for (int i = 0; i < n; i++) {
42+
cin >> a[i];
43+
}
44+
45+
for (int i = 0; i < n; i++) {
46+
cin >> b[i];
47+
}
48+
49+
int count = 0;
50+
51+
// 遍历所有可能的区间
52+
for (int left = 0; left < n; left++) {
53+
for (int right = left; right < n; right++) {
54+
// 检查翻转区间 [left, right] 后,a 是否可以变成 b
55+
if (canTransform(a, b, left, right)) {
56+
count++;
57+
}
58+
}
59+
}
60+
cout << count << endl;
61+
return 0;
62+
}
63+
```
64+
65+
也可以事先计算好,最长公共前缀,和最长公共后缀。
66+
67+
在公共前缀和公共后缀之间的部分进行翻转操作,这样我们可以减少很多不必要的翻转尝试。
68+
69+
通过在公共前缀和后缀之间的部分,找到可以通过翻转使得 a 和 b 相等的区间。
70+
71+
以下 为评论区 卡码网用户:码鬼的C++代码
72+
73+
```CPP
74+
#include <iostream>
75+
#include <vector>
76+
77+
using namespace std;
78+
79+
int main() {
80+
int n;
81+
cin >> n;
82+
vector<int> a(n), b(n);
83+
for (int i = 0; i < n; i++) {
84+
cin >> a[i];
85+
}
86+
for (int i = 0; i < n; i++) {
87+
cin >> b[i];
88+
}
89+
90+
vector<int> prefix(n, 0), suffix(n, 0);
91+
92+
// 计算前缀相等的位置
93+
int p = 0;
94+
while (p < n && a[p] == b[p]) {
95+
prefix[p] = 1;
96+
p++;
97+
}
98+
99+
// 计算后缀相等的位置
100+
int s = n - 1;
101+
while (s >= 0 && a[s] == b[s]) {
102+
suffix[s] = 1;
103+
s--;
104+
}
105+
106+
int count = 0;
107+
108+
// 遍历所有可能的区间
109+
for (int i = 0; i < n - 1; i++) {
110+
for (int j = i + 1; j < n; j++) {
111+
// 判断前缀和后缀是否相等
112+
if ((i == 0 || prefix[i - 1] == 1) && (j == n - 1 || suffix[j + 1] == 1)) {
113+
// 判断翻转后的子数组是否和目标数组相同
114+
bool is_palindrome = true;
115+
for (int k = 0; k <= (j - i) / 2; k++) {
116+
if (a[i + k] != b[j - k]) {
117+
is_palindrome = false;
118+
break;
119+
}
120+
}
121+
if (is_palindrome) {
122+
count++;
123+
}
124+
}
125+
}
126+
}
127+
128+
cout << count << endl;
129+
130+
return 0;
131+
}
132+
```

0 commit comments

Comments
 (0)