Skip to content

Commit 30d4065

Browse files
committed
codes/c: chapter_backtracking
climbing_stairs_dfs1.c climbing_stairs_dfs_mem1.c climbing_stairs_dp1.c knapsack1.c unbounded_knapsack1.c edit_distance1.c
1 parent a01bdcd commit 30d4065

6 files changed

Lines changed: 510 additions & 0 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include "../utils/common.h"
2+
3+
/* 搜索 */
4+
int dfs(int i) {
5+
// 已知 dp[1] 和 dp[2],返回之
6+
if (i == 1 || i == 2)
7+
return i;
8+
// dp[i] = dp[i - 1] + dp[i - 2]
9+
int count = dfs(i -1) + dfs(i -2);
10+
return count;
11+
}
12+
13+
/* 爬楼梯:搜索 */
14+
int climbingStairsDFS(int n) {
15+
return dfs(n);
16+
}
17+
18+
/* Driver Code */
19+
int main() {
20+
int n = 9;
21+
22+
int res = climbingStairsDFS(n);
23+
printf("爬 %d 阶楼梯共有 %d 种方案\n", n, res);
24+
25+
return 0;
26+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "../utils/common.h"
2+
3+
/* 记忆搜索 */
4+
int dfs(int i, int *mem) {
5+
// 已知 dp[1] 和dp[2],返回之
6+
if(i == 1 || i == 2)
7+
return i;
8+
// 若存在记录 dp[i],则直接返回之
9+
if(mem[i] != -1)
10+
return mem[i];
11+
// dp[i] = dp[i - 1] + dp[i -2];
12+
int count = dfs(i - 1, mem) + dfs(i - 2, mem);
13+
// 记录 dp[i]
14+
mem[i] = count;
15+
return count;
16+
}
17+
18+
/* 爬楼梯:记忆搜索 */
19+
int climbingStairsDFSMem(int n) {
20+
// mem[i] 记录爬到第 i 阶的方案总数,-1 代表无记录
21+
int *mem = (int *)malloc((n + 1) * sizeof(int));
22+
for (int i = 0; i <=n; i++) {
23+
mem[i] = -1;
24+
}
25+
int result = dfs(n, mem);
26+
free(mem);
27+
return result;
28+
}
29+
30+
/* Driver Code */
31+
int main() {
32+
int n = 9;
33+
int res = climbingStairsDFSMem(n);
34+
printf("爬 %d 阶楼梯共有 %d 种方案\n", n, res);
35+
36+
return 0;
37+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include "../utils/common.h"
2+
3+
/* 爬楼梯:动态规划 */
4+
int climbingStairsDP(int n) {
5+
if(n == 1 || n ==2)
6+
return n;
7+
// 初始化 dp 表,用于存储子问题的解
8+
int *dp = (int *)malloc((n + 1) * sizeof(int));
9+
// 初始状态:预设最小子问题的解
10+
dp[1] = 1;
11+
dp[2] = 2;
12+
// 状态转移:从较小子问题逐步求解较大子问题
13+
for (int i = 3; i <= n; i++) {
14+
dp[i] = dp[i -1] + dp[i - 2];
15+
}
16+
int result = dp[n];
17+
free(dp);
18+
return result;
19+
}
20+
21+
/* 爬楼梯:空间优化后的动态规划 */
22+
int climbingStairsDPComp(int n) {
23+
if(n == 1 | n ==2)
24+
return n;
25+
int a = 1, b =2;
26+
for (int i = 3; i <=n; i++) {
27+
int tmp = b;
28+
b = a + b;
29+
a = tmp;
30+
}
31+
return b;
32+
}
33+
34+
/* Driver Code */
35+
int main() {
36+
int n = 9;
37+
38+
int res = climbingStairsDP(n);
39+
printf("爬 %d 阶楼梯共有 %d 种方案\n", n, res);
40+
41+
res = climbingStairsDPComp(n);
42+
printf("爬 %d 阶楼梯共有 %d 种方案\n", n, res);
43+
44+
return 0;
45+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#include "../utils/common.h"
2+
3+
/* 求最小值 */
4+
int myMin(int a, int b) {
5+
return a < b ? a : b;
6+
}
7+
8+
/* 编辑距离:暴力搜索 */
9+
int editDistanceDFS(char *s, char *t, int i, int j) {
10+
// 若 s 和 t 都为空,则返回 0
11+
if (i == 0 && j == 0)
12+
return 0;
13+
// 若 s 为空,则返回 t 长度
14+
if (i == 0)
15+
return j;
16+
// 若 t 为空,则返回 s 长度
17+
if (j == 0)
18+
return i;
19+
// 若两字符相等,则直接跳过此字符
20+
if (s[i - 1] == t[j - 1])
21+
return editDistanceDFS(s, t, i - 1, j - 1);
22+
// 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1
23+
int insert = editDistanceDFS(s, t, i, j - 1);
24+
int del = editDistanceDFS(s, t, i - 1, j);
25+
int replace = editDistanceDFS(s, t, i - 1, j -1);
26+
// 返回最少编辑步数
27+
return myMin(myMin(insert, del), replace) + 1;
28+
}
29+
30+
/* 编辑距离:记忆搜索优化 */
31+
int editDistanceDFSMem(char *s, char *t, int memCols, int **mem, int i, int j) {
32+
// 若 s 和 t 都为空,则返回 0
33+
if (i == 0 && j == 0)
34+
return 0;
35+
// 若 s 为空,则返回 t 长度
36+
if (i == 0)
37+
return j;
38+
// 若 t 为空,则返回 s 长度
39+
if (j == 0)
40+
return i;
41+
// 若已有记录,则直接返回之
42+
if (mem[i][j] != -1)
43+
return mem[i][j];
44+
// 若两字符相等,则直接跳过此字符
45+
if (s[i - 1] == t[j - 1])
46+
return editDistanceDFSMem(s, t, memCols, mem, i - 1, j - 1);
47+
// 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1
48+
// 若已有记录,则直接返回之
49+
int insert = editDistanceDFSMem(s, t, memCols, mem, i, j - 1);
50+
int del = editDistanceDFSMem(s, t, memCols, mem, i - 1, j);
51+
int replace = editDistanceDFSMem(s, t, memCols, mem, i - 1, j -1);
52+
// 返回最少编辑步数
53+
mem[i][j] = myMin(myMin(insert, del), replace) + 1;
54+
return mem[i][j];
55+
}
56+
57+
/* 编辑距离:动态规划 */
58+
int editDistanceDP(char *s, char *t, int n, int m) {
59+
int **dp = malloc((n + 1) * sizeof(int *));
60+
for (int i = 0; i <= n; i++) {
61+
dp[i] = calloc(m + 1, sizeof(int));
62+
}
63+
// 状态转移:首行首列
64+
for (int i = 1; i <= n; i++) {
65+
dp[i][0] = i;
66+
}
67+
for (int j = 1; j <= m; j++) {
68+
dp[0][j] = j;
69+
}
70+
// 状态转移:其余行和列
71+
for (int i = 1; i <= n; i++) {
72+
for (int j = 1; j <= m; j++){
73+
if (s[i - 1] == t[j - 1]) {
74+
// 若两字符相等,则直接跳过此两字符
75+
dp[i][j] = dp[i - 1][j - 1];
76+
} else {
77+
// 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1
78+
dp[i][j] = myMin(myMin(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
79+
}
80+
}
81+
}
82+
int res = dp[n][m];
83+
// 释放内存
84+
for (int i = 0; i <= n; i++) {
85+
free(dp[i]);
86+
}
87+
return res;
88+
}
89+
90+
/* 编辑距离:空间优化后的动态规划 */
91+
int editDistanceDPComp(char *s, char *t, int n, int m) {
92+
int *dp = calloc(m + 1, sizeof(int));
93+
// 状态转移:首行
94+
for (int j = 1; j <= m; j++) {
95+
dp[j] = j;
96+
}
97+
// 状态转移:其余行
98+
for (int i = 1; i <= n; i++) {
99+
// 状态转移:首列
100+
int leftup = dp[0]; // 暂存 dp[i - 1, j - 1]
101+
dp[0] = i;
102+
// 状态转移:其余列
103+
for (int j = 1; j <= m; j ++) {
104+
int temp = dp[j];
105+
if (s[i -1] == t[j - 1]) {
106+
// 若两字符相等,则直接跳过此两字符
107+
dp[j] = leftup;
108+
} else {
109+
// 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1
110+
dp[j] = myMin(myMin(dp[j - 1], dp[j]), leftup) + 1;
111+
}
112+
leftup = temp; // 更新为下一轮的 dp[i - 1, j -1]
113+
}
114+
}
115+
int res = dp[m];
116+
// 释放内存
117+
free(dp);
118+
return res;
119+
}
120+
121+
/* Driver Code */
122+
int main() {
123+
char *s = "bag";
124+
char *t = "pack";
125+
int n = strlen(s), m = strlen(t);
126+
127+
// 暴力搜索
128+
int res = editDistanceDFS(s, t, n, m);
129+
printf("将 %s 更改为 %s 最少需要编辑 %d 步\n", s, t, res);
130+
131+
// 记忆化搜索
132+
int **mem = malloc((n + 1) * sizeof(int *));
133+
for (int i = 0; i <= n; i ++) {
134+
mem[i] = malloc((m + 1) * sizeof(int));
135+
memset(mem[i], -1, (m + 1) * sizeof(int));
136+
}
137+
res = editDistanceDFSMem(s, t, m + 1, mem, n, m);
138+
printf("将 %s 更改为 %s 最少需要编辑 %d 步\n", s, t, res);
139+
// 释放内存
140+
for (int i = 0; i <= n; i++) {
141+
free(mem[i]);
142+
}
143+
free(mem);
144+
145+
// 动态规划
146+
res = editDistanceDP(s, t, n, m);
147+
printf("将 %s 更改为 %s 最少需要编辑 %d 步\n", s, t, res);
148+
149+
// 空间优化后的动态规划
150+
res = editDistanceDPComp(s, t, n, m);
151+
printf("将 %s 更改为 %s 最少需要编辑 %d 步\n", s, t, res);
152+
153+
return 0;
154+
}

0 commit comments

Comments
 (0)