深度优先搜索DFS本身很好理解,即按照一定顺序递归遍历一个图,但是如何把所有的满足要求的遍历方式给求出来,这里就需要结合回溯backtrace了。
在LeetCode中,回溯标签下的很多题目都是求排列组合的,这也算是一类经典类型的题目了。C/C++写的多人都会有个特点:写代码的时候脑子里都是内存布局,栈帧结构,以及代码执行时各个对象的生命周期等等,写的多了某种程度可以对这些东西做到可视化了都。理解DFS回溯,就把这个递归调用的调用栈帧以及关键全局变量的修改在脑子给推演一下,就很容易理解了。如果还做不到这点,到时可以动笔画图辅助一下。
组合 C n k C_n^k Cnk
https://leetcode-cn.com/problems/combinations/
int g_retNum = 0;
int g_arr[10240];
int g_pos = 0;
void dfs(int **re, int n, int k, int start)
{
// 深搜的递归终止条件
if (g_pos == k) {
re[g_retNum] = malloc(sizeof(int) * k);
memcpy(re[g_retNum], g_arr, sizeof(int) * k);
g_retNum++;
return;
}
for (int i = start; i <= n; i++) {
g_arr[g_pos++] = i;
dfs(re, n, k, i + 1);
g_pos--; // 递归路径的回溯
}
}
int **combine(int n, int k, int *returnSize, int **returnColumnSizes)
{
// 初始化全局变量,C没有class,变量都通过入参传递太麻烦,适当用全局变量
// 控制好这些全局变量的访问就好,可以加上static修饰等
g_retNum = 0;
g_pos = 0;
int **re = malloc(sizeof(int *) * 10240);
dfs(re, n, k, 1);
*returnSize = g_retNum;
*returnColumnSizes = malloc(sizeof(void *) * g_retNum);
for (int i = 0; i < g_retNum; i++) {
(*returnColumnSizes)[i] = k;
}
return re;
}
全排列 A n k A_n^k Ank
https://leetcode-cn.com/problems/permutations/
int g_num = 0;
int g_arr[10240];
int g_pos = 0;
bool g_visited[10240];
void dfs(int **re, int *nums, int numsSize, int start)
{
// DFS递归的终止条件,并搜集一轮结果
if (g_pos == numsSize) {
re[g_num] = malloc(sizeof(int) * numsSize);
memcpy(re[g_num], g_arr, sizeof(int) * numsSize);
g_num++;
return;
}
for (int i = start; i < numsSize; i++) {
if (g_visited[i]) continue; // 访问过的减枝
g_arr[g_pos++] = nums[i];
g_visited[i] = true;
dfs(re, nums, numsSize, 0); // 排列每次都从头访问,,略过前面访问过
g_pos--;
g_visited[i] = false;
}
}
int **permute(int *nums, int numsSize, int *returnSize, int **returnColumnSizes)
{
// 初始化全局变量,C没有class,变量都通过入参传递太麻烦,适当用全局变量
// 控制好这些全局变量的访问就好,可以加上static修饰等
g_num = 0;
g_pos = 0;
memset(g_visited, false, sizeof(g_visited));
int **re = malloc(sizeof(int *) * 10240);
dfs(re, nums, numsSize, 0);
*returnSize = g_num;
*returnColumnSizes = malloc(sizeof(void *) * g_num);
for (int i = 0; i < g_num; i++) {
(*returnColumnSizes)[i] = numsSize;
}
return re;
}
还有很多类似题目,基本都可以用这种方法解决。