Skip to content

Commit 696bf34

Browse files
committed
update doc
1 parent 0e3b41f commit 696bf34

File tree

9 files changed

+287
-56
lines changed

9 files changed

+287
-56
lines changed

dev/.project.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ let g:nvim_lsp_autostart = {'clangd': v:true}
44
" Disable AI completion
55
let g:copilot_filetypes = { '*': v:false }
66

7+
set norelativenumber

doc/graph-edge-type.png

23.7 KB
Loading

doc/图论.md

Lines changed: 171 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,123 @@
22

33
[TOC]
44

5+
## 判断树边,前向边,回边,横跨边
6+
7+
- https://blog.csdn.net/u014665013/article/details/51351371
8+
9+
![graph-edge-type](./graph-edge-type.png)
10+
11+
- https://blog.csdn.net/wshish920907/article/details/73276813
12+
13+
visited数组取值0, 1, 2
14+
15+
0, 尚未访问,表示树边。1,孩子还没访问完,表示回边。2,孩子访问完了,表示前向边/横跨边。
16+
17+
可以增加一个时间戳,记录每个节点首次访问的时间戳(访问dfs序)。当visited=2时,对于边 u -> v,若u的时间戳小于v的时间戳,则是前向边,否则是横跨边。
18+
19+
### 判断有没有环
20+
21+
即判断是否存在回边
22+
23+
https://leetcode.cn/problems/course-schedule/?envType=problem-list-v2&envId=graph
24+
25+
```cpp
26+
class Solution {
27+
bool result = true;
28+
void doDfs(
29+
int &ts,
30+
std::vector<int> &visited,
31+
std::vector<int> &order,
32+
std::vector<std::vector<int>> &graph,
33+
int cur_node
34+
) {
35+
if (order[cur_node] > 0) {
36+
return;
37+
}
38+
order[cur_node] = ts++;
39+
visited[cur_node] = 1;
40+
for (auto child : graph[cur_node]) {
41+
if (visited[child] == 0) {
42+
// tree edge
43+
} else if (visited[child] == 1) {
44+
// backward edge
45+
result = false;
46+
} else {
47+
// cross edge or forward edge
48+
if (order[cur_node] < order[child]) {
49+
// forword edge
50+
} else {
51+
// cross edge
52+
}
53+
}
54+
doDfs(ts, visited, order, graph, child);
55+
}
56+
visited[cur_node] = 2;
57+
}
58+
void dfs(std::vector<std::vector<int>> &graph) {
59+
int ts = 1;
60+
result = true;
61+
std::vector<int> visited(graph.size(), 0), order(graph.size(), 0);
62+
for (int i = 0; i < graph.size(); ++i) {
63+
if (visited[i] == 0) {
64+
doDfs(ts, visited, order, graph, i);
65+
}
66+
}
67+
}
68+
public:
69+
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
70+
std::vector<std::vector<int>> graph(numCourses);
71+
for (auto &p : prerequisites) {
72+
graph[p[1]].push_back(p[0]);
73+
}
74+
75+
dfs(graph);
76+
return result;
77+
}
78+
};
79+
```
80+
581
## 拓扑排序
682

783
节点带权重,在满足拓扑序的情况下,按权重高低优先输出。
884

985
思路:利用优先队列作为中间结构,每次将入度为0的点加入优先队列,然后取出最高优先级的点,并更新该点所有邻接点的入度,如果入度为0,则加入优先队列。
1086

87+
```cpp
88+
class Solution {
89+
public:
90+
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
91+
std::vector<std::vector<int>> graph(numCourses);
92+
std::vector<int> in_degree(numCourses);
93+
94+
for (auto &e : prerequisites) {
95+
graph[e[1]].push_back(e[0]);
96+
in_degree[e[0]]++;
97+
}
98+
99+
std::queue<int> in_q;
100+
for (int i = 0; i < in_degree.size(); ++i) {
101+
if (in_degree[i] == 0) {
102+
in_q.push(i);
103+
}
104+
}
105+
std::vector<int> learn_order;
106+
while (!in_q.empty()) {
107+
auto node = in_q.front();
108+
in_q.pop();
109+
learn_order.push_back(node);
110+
for (auto child : graph[node]) {
111+
in_degree[child]--;
112+
if (in_degree[child] == 0) {
113+
in_q.push(child);
114+
}
115+
}
116+
}
117+
return learn_order.size() == numCourses ? learn_order : std::vector<int>();
118+
}
119+
};
120+
```
121+
11122
## 二分图
12123

13124
### 性质
@@ -980,6 +1091,12 @@ O(ElgV)
9801091
9811092
## 树
9821093
1094+
### 图判树
1095+
1096+
方法一: 图连通且边数等于点数减一就是树。
1097+
1098+
方法二: 从任意一点开始DFS,如果DFS过程中有环,那么不是树。同时整个图必须是连通的。
1099+
9831100
### LCA
9841101
9851102
倍增求LCA
@@ -1079,12 +1196,64 @@ int main() {
10791196

10801197
### 树的直径
10811198

1082-
### 两次dfs
1199+
#### 解法
1200+
##### 两次dfs/bfs
10831201

10841202
先从任意一点P出发,找离它最远的点Q,再从点Q出发,找离它最远的点W,W到Q的距离就是是的直径
10851203

1086-
### 树形DP
1204+
##### 树形DP
10871205

1206+
#### 树的中心
1207+
1208+
树的中心: 所有节点中,到树中其他节点的最远距离 最小的节点。树的中心有1个或2个。
1209+
1210+
```c++
1211+
1212+
[leetcode例题](https://leetcode.cn/problems/minimum-height-trees)
1213+
1214+
```c++
1215+
class Solution {
1216+
public:
1217+
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
1218+
std::vector<std::vector<int>> graph(n);
1219+
for (auto &e : edges) {
1220+
graph[e[0]].push_back(e[1]);
1221+
graph[e[1]].push_back(e[0]);
1222+
}
1223+
std::vector<int> parents(n, -1);
1224+
int x = bfs(graph, parents, 0);
1225+
int y = bfs(graph, parents, x);
1226+
std::vector<int> path;
1227+
while (y != -1) {
1228+
path.push_back(y);
1229+
y = parents[y];
1230+
}
1231+
return path.size() % 2 == 1 ? std::vector({path[path.size() / 2]}) : std::vector({path[path.size() / 2 - 1], path[path.size() / 2]});
1232+
}
1233+
1234+
int bfs(const std::vector<std::vector<int>> &graph,
1235+
std::vector<int> &parents,
1236+
int cur_node) {
1237+
parents[cur_node] = -1;
1238+
std::vector<bool> visited(graph.size(), false);
1239+
visited[cur_node] = true;
1240+
std::queue<int> q;
1241+
q.push(cur_node);
1242+
while (!q.empty()) {
1243+
cur_node = q.front();
1244+
q.pop();
1245+
for (auto child : graph[cur_node]) {
1246+
if (!visited[child]) {
1247+
parents[child] = cur_node;
1248+
q.push(child);
1249+
visited[child] = true;
1250+
}
1251+
}
1252+
}
1253+
return cur_node;
1254+
}
1255+
};
1256+
```
10881257

10891258
## 参考文献
10901259

doc/数学.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,38 @@
22

33
[TOC]
44

5+
## 计算机取模运算
6+
7+
$A % B = A - A / B * B$
8+
9+
结果只和左操作数有关:当左操作数为负数时,结果为负数或0;当左操作数为正数时,结果为正数或0。
10+
11+
## 两数相除
12+
13+
https://leetcode.cn/problems/divide-two-integers/
14+
15+
```c++
16+
class Solution {
17+
public:
18+
int divide(const int dividend, const int divisor) {
19+
if (dividend == INT_MIN && divisor == -1) return INT_MAX;
20+
if (dividend == INT_MIN && divisor == 1) return INT_MIN;
21+
if (dividend > 0) return -divide(-dividend, divisor);
22+
if (divisor > 0) return -divide(dividend, -divisor);
23+
// 转换为负数 / 负数,防止溢出
24+
if (dividend > divisor) return 0;
25+
int sub = divisor;
26+
int result = 1;
27+
// 防止sub + sub溢出
28+
while (dividend - sub <= sub) {
29+
result += result;
30+
sub += sub;
31+
}
32+
return result + divide(dividend - sub, divisor);
33+
}
34+
};
35+
```
36+
537
## 约瑟夫环/约瑟夫问题
638
739
## 快速幂/快速幂取模/费马小定理

doc/数据结构.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,20 @@ int main() {
115115

116116
## 树状数组
117117

118+
树状数组特点:
119+
120+
- 每一层内,末尾0的个数均相同,第一层0个0,第二次1个0...
121+
- 单点更新:节点x的父节点为x+lowbit(x)
122+
- 区间查询:不停地减去lowbit(x)直到x为0
123+
124+
https://blog.csdn.net/TheWayForDream/article/details/118436732
125+
118126
```c++
119127
class TreeArr {
120128
int n;
121129
vector<int> inner;
122130

131+
// ((Not x)+1) And x,即求x的最低位1
123132
constexpr int lowbit(int x) {
124133
return x & (-x);
125134
}

doc/数论.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -780,10 +780,11 @@ bool is_prime(a) {
780780

781781
void sieve(int n) {
782782
memset(is_prime, true, sizeof(is_prime));
783+
is_prime[1] = false;
783784
for (int i = 2; i <= n; ++i) {
784785
if (is_prime[i]) {
785786
primes.push_back(i);
786-
for (int j = i + i; j <= n; j += i) {
787+
for (int j = i * i; j <= n; j += i) {
787788
is_prime[j] = false;
788789
}
789790
}
@@ -1279,4 +1280,4 @@ int main() {
12791280
printf("%lld\n", Min25::solve(n));
12801281
return 0;
12811282
}
1282-
```
1283+
```

doc/算法基础.md

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,52 @@
11
# 算法基础
22

3+
## 二分查找
4+
5+
https://leetcode.cn/problems/binary-search/?envType=problem-list-v2&envId=binary-search
6+
7+
非递归
8+
```cpp
9+
class Solution {
10+
public:
11+
int search(vector<int>& nums, int target) {
12+
int left = 0;
13+
int right = nums.size() - 1;
14+
while (left <= right) {
15+
int mid = (left + right) / 2;
16+
if (nums[mid] == target) return mid;
17+
if (nums[mid] < target) left = mid + 1;
18+
else right = mid - 1;
19+
}
20+
return -1;
21+
}
22+
};
23+
```
24+
25+
寻找旋转数组最小值
26+
27+
有时候循环条件是`left < right`,有时候是`left <= right`,具体看题目要求。
28+
数组长度为2时,`left == mid`,所以`left`必须`left = mid + 1`,否则会死循环。
29+
如果希望`right`不会比`left`小,那么`right = mid`,否则`right = mid - 1`。
30+
31+
```cpp
32+
class Solution {
33+
public:
34+
int findMin(vector<int>& nums) {
35+
int left = 0;
36+
int right = nums.size() - 1;
37+
while (left < right) {
38+
int mid = (left + right) / 2;
39+
if (nums[mid] > nums.back()) {
40+
left = mid + 1;
41+
} else {
42+
right = mid;
43+
}
44+
}
45+
return nums[left];
46+
}
47+
};
48+
```
49+
350
## 前缀和
451

552
CF1426D:给一个长为n的序列,求至少插入几个数,使得连续子序列的和均不为0
@@ -42,7 +89,18 @@ int main() {
4289

4390
```
4491

45-
## 双指针
92+
## 滑动窗口 [interview]
93+
94+
[Leetcode](https://leetcode.cn/problems/subarray-product-less-than-k/description/?envType=problem-list-v2&envId=sliding-window)
95+
96+
## 双指针 [interview]
4697

4798
[Leetcode 盛水最多的容器](https://leetcode.cn/problems/container-with-most-water/description/?envType=study-plan-v2&envId=top-100-liked)
4899

100+
## 单调栈 [interview]
101+
102+
[接雨水](https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/?envType=company&envId=bytedance&favoriteSlug=bytedance-thirty-days)
103+
104+
维护一个单调递减的栈
105+
106+
[去除重复字母](https://leetcode.cn/problems/remove-duplicate-letters/?envType=company&envId=bytedance&favoriteSlug=bytedance-thirty-days)

doc/编程语言.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,18 @@ erase 1
126126
3 2 0
127127
```
128128

129+
130+
### std::stack
131+
132+
`std::string` 也可以当作栈使用。
133+
134+
```c++
135+
std::string s;
136+
s.push_back('a');
137+
s.back();
138+
s.pop_back();
139+
```
140+
129141
## Java
130142

131143
快读

0 commit comments

Comments
 (0)