Skip to content

Commit 2db2fe7

Browse files
committed
update dp
1 parent a582f25 commit 2db2fe7

File tree

8 files changed

+386
-730
lines changed

8 files changed

+386
-730
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Codes and documentations for algorithms.
44

55
POJ, lintcode, 洛谷, 牛客, 计蒜客, leetcode, hduoj
66

7+
https://oi-wiki.org/
8+
79
## Development Environment
810

911
### 牛客网

doc/asset/LIS.png

220 KB
Loading

doc/动态规划.md

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,126 @@ public:
113113

114114
```
115115
116+
## 最长公共子串 [interview]
116117
118+
dp[i][j]表示在str1中以第i个字符结尾,在str2中以第j个字符结尾时的公共子串长度。
119+
120+
$$
121+
dp(i, j) = \begin{cases}
122+
dp(i-1, j-1) + 1 & str1[i] = str2[j] \\
123+
0 & str1[i] \neq str2[j]
124+
\end{cases}
125+
$$
126+
127+
牛客 NC127 最长公共子串
128+
```cpp
129+
class Solution {
130+
public:
131+
string LCS(string str1, string str2) {
132+
//dp[i][j]表示到str1第i个个到str2第j个为止的公共子串长度
133+
vector<vector<int> > dp(str1.length() + 1, vector<int>(str2.length() + 1, 0));
134+
int max = 0;
135+
int pos = 0;
136+
for(int i = 1; i <= str1.length(); i++){
137+
for(int j = 1; j <= str2.length(); j++){
138+
//如果该两位相同
139+
if(str1[i - 1] == str2[j - 1]){
140+
//则增加长度
141+
dp[i][j] = dp[i - 1][j - 1] + 1;
142+
}
143+
else{
144+
//该位置为0
145+
dp[i][j] = 0;
146+
}
147+
//更新最大长度
148+
if(dp[i][j] > max){
149+
max = dp[i][j];
150+
pos = i - 1;
151+
}
152+
}
153+
}
154+
return str1.substr(pos - max + 1, max);
155+
}
156+
};
157+
```
158+
159+
## 最长公共子序列 [interview]
160+
161+
f(i, j)表示只考虑序列A前i个元素,序列B前j个元素的最长公共子序列时的长度。
162+
163+
$$
164+
f(i, j) = \begin{cases}
165+
f(i-1, j-1) + 1 & A[i] = B[j] \\
166+
max(f(i-1, j), f(i, j-1)) & A[i] \neq B[j]
167+
\end{cases}
168+
$$
169+
170+
如果要输出最长公共子序列,可以根据dp数组逆推。
171+
172+
牛客BM65 最长公共子序列(二)
173+
```cpp
174+
class Solution {
175+
public:
176+
string LCS(string s1, string s2) {
177+
//只要有一个空字符串便不会有子序列
178+
if(s1.length() == 0 || s2.length() == 0)
179+
return "-1";
180+
int len1 = s1.length();
181+
int len2 = s2.length();
182+
//dp[i][j]表示第一个字符串到第i位,第二个字符串到第j位为止的最长公共子序列长度
183+
vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0));
184+
//遍历两个字符串每个位置求的最长长度
185+
for(int i = 1; i <= len1; i++){
186+
for(int j = 1; j <= len2; j++){
187+
//遇到两个字符相等
188+
if(s1[i - 1] == s2[j -1])
189+
//来自于左上方
190+
dp[i][j] = dp[i - 1][j - 1] + 1;
191+
//遇到的两个字符不同
192+
else
193+
//来自左边或者上方的最大值
194+
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
195+
}
196+
}
197+
//从动态规划数组末尾开始
198+
int i = len1, j = len2;
199+
stack<char> s;
200+
while(dp[i][j]){
201+
//来自于左方向
202+
if(dp[i][j] == dp[i - 1][j])
203+
i--;
204+
//来自于上方向
205+
else if(dp[i][j] == dp[i][j - 1])
206+
j--;
207+
//来自于左上方向
208+
else if(dp[i][j] > dp[i - 1][j - 1]){
209+
i--;
210+
j--;
211+
//只有左上方向才是字符相等的情况,入栈,逆序使用
212+
s.push(s1[i]);
213+
}
214+
}
215+
string res = "";
216+
//拼接子序列
217+
while(!s.empty()){
218+
res += s.top();
219+
s.pop();
220+
}
221+
//如果两个完全不同,返回字符串为空,则要改成-1
222+
return res != "" ? res : "-1";
223+
}
224+
};
225+
```
117226
118227
## 最长递增子序列
119228
229+
![LIS](./asset/LIS.png)
230+
231+
[图片来源](https://github.com/labuladong/fucking-algorithm/blob/master/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E7%B3%BB%E5%88%97/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E8%AE%BE%E8%AE%A1%EF%BC%9A%E6%9C%80%E9%95%BF%E9%80%92%E5%A2%9E%E5%AD%90%E5%BA%8F%E5%88%97.md)
232+
### 仅输出长度
233+
234+
二分查找 $$O(nlogn)$$
235+
120236
```c++
121237
// 严格递增
122238
#include <cstdio>
@@ -128,7 +244,7 @@ int arr[MAX_N] = {0};
128244
int main() {
129245
int n;
130246
scanf("%d", &n);
131-
247+
132248
int element, idx = 0;
133249
int *index;
134250
for (int i = 0; i < n; ++i) {
@@ -160,7 +276,9 @@ std::vector<int> get_lcs(const std::vector<int> &vec) {
160276
}
161277
```
162278
163-
##### 求逆序对的个数
279+
### 打印序列
280+
281+
### 求逆序对的个数
164282
165283
相当于原序列长度-最长递增子序列长度
166284

doc/图论.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
[TOC]
44

5+
## 拓扑排序
56

7+
节点带权重,在满足拓扑序的情况下,按权重高低优先输出。
8+
9+
思路:利用优先队列作为中间结构,每次将入度为0的点加入优先队列,然后取出最高优先级的点,并更新该点所有邻接点的入度,如果入度为0,则加入优先队列。
610

711
## 二分图
812

@@ -974,6 +978,113 @@ int main() {
974978
O(ElgV)
975979
976980
981+
## 树
982+
983+
### LCA
984+
985+
倍增求LCA
986+
987+
```C++
988+
/**
989+
* luogu3379
990+
*/
991+
992+
#include <cstdio>
993+
#include <algorithm>
994+
995+
using namespace std;
996+
997+
struct Edge {
998+
int v;
999+
int next;
1000+
} edges[500002 << 1];
1001+
int heads[500002];
1002+
int total = 0;
1003+
1004+
int depth[500002] = {0};
1005+
int ancestors[500002][22] = {0};
1006+
1007+
int LOG_2[500002];
1008+
1009+
void add_edge(int u, int v) {
1010+
edges[++total] = {v, heads[u]};
1011+
heads[u] = total;
1012+
}
1013+
1014+
void dfs(int cur_v, int parent) {
1015+
ancestors[cur_v][0] = parent;
1016+
depth[cur_v] = depth[parent] + 1;
1017+
1018+
for (int i = 1; i <= LOG_2[depth[cur_v]]; ++i) {
1019+
ancestors[cur_v][i] = ancestors[ancestors[cur_v][i-1]][i-1];
1020+
}
1021+
1022+
for (int i = heads[cur_v]; i; i = edges[i].next) {
1023+
if (edges[i].v != parent) {
1024+
dfs(edges[i].v, cur_v);
1025+
}
1026+
}
1027+
}
1028+
1029+
int lca(int a, int b) {
1030+
if (depth[a] < depth[b]) {
1031+
swap(a, b);
1032+
}
1033+
while (depth[a] > depth[b]) {
1034+
a = ancestors[a][LOG_2[depth[a]-depth[b]]];
1035+
}
1036+
if (a == b) {
1037+
return a;
1038+
}
1039+
for (int i = LOG_2[depth[a]]; i >= 0; --i) {
1040+
if (ancestors[a][i] != ancestors[b][i]) {
1041+
a = ancestors[a][i];
1042+
b = ancestors[b][i];
1043+
}
1044+
}
1045+
return ancestors[a][0];
1046+
}
1047+
1048+
void get_log_2() {
1049+
LOG_2[1] = 0;
1050+
for (int i = 2; i <= 500001; ++i) {
1051+
LOG_2[i] = LOG_2[i>>1] + 1;
1052+
}
1053+
}
1054+
1055+
int main() {
1056+
get_log_2();
1057+
1058+
int n, m, s;
1059+
scanf("%d %d %d", &n, &m, &s);
1060+
1061+
int x, y;
1062+
for (int i = 0; i < n - 1; ++i) {
1063+
scanf("%d %d", &x, &y);
1064+
add_edge(x, y);
1065+
add_edge(y, x);
1066+
}
1067+
1068+
dfs(s, 0);
1069+
1070+
int a, b;
1071+
for (int i = 0; i < m; ++i) {
1072+
scanf("%d %d", &a, &b);
1073+
printf("%d\n", lca(a, b));
1074+
}
1075+
1076+
return 0;
1077+
}
1078+
```
1079+
1080+
### 树的直径
1081+
1082+
### 两次dfs
1083+
1084+
先从任意一点P出发,找离它最远的点Q,再从点Q出发,找离它最远的点W,W到Q的距离就是是的直径
1085+
1086+
### 树形DP
1087+
9771088

9781089
## 参考文献
9791090

doc/字符串.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ int main() {
6161
}
6262
```
6363
64+
利用KMP算法中的get_next()可以求字符串最大回文前缀(cf1326D)
65+
6466
## 字符串哈希
6567
6668
```c++

doc/数据结构.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,3 +506,60 @@ int main() {
506506
}
507507
```
508508
509+
## LRU Cache
510+
511+
迭代器变量声明: `std::unordered_map<int, std::list<Entry>::iterator> map;`
512+
513+
[牛客BM100 设计LRU缓存结构](https://www.nowcoder.com/practice/5dfded165916435d9defb053c63f1e84?tpId=295&tqId=2427094&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj)
514+
515+
```cpp
516+
#include <cassert>
517+
#include <list>
518+
#include <unordered_map>
519+
520+
class Solution {
521+
using Entry = std::pair<int, int>;
522+
523+
public:
524+
Solution(int capacity) : capacity(capacity) {
525+
}
526+
527+
int get(int key) {
528+
auto it = map.find(key);
529+
if (it == map.end()) {
530+
return -1;
531+
}
532+
assert(it->first == key);
533+
auto t = it->second;
534+
assert(t->first == key);
535+
int result = t->second;
536+
entries.erase(t);
537+
doSet(key, result);
538+
return result;
539+
}
540+
541+
void set(int key, int value) {
542+
auto it = map.find(key);
543+
if (it != map.end()) {
544+
map.erase(it);
545+
}
546+
547+
doSet(key, value);
548+
}
549+
private:
550+
551+
void doSet(int key, int value) {
552+
auto it = entries.emplace_front(key, value);
553+
map[key] = entries.begin();
554+
if (entries.size() > capacity) {
555+
map.erase(entries.back().first);
556+
entries.pop_back();
557+
assert(entries.size() == capacity);
558+
}
559+
}
560+
int capacity;
561+
562+
std::list<Entry> entries;
563+
std::unordered_map<int, std::list<Entry>::iterator> map;
564+
};
565+
```

0 commit comments

Comments
 (0)