一.DFS-回溯引入
(1)递归深度
输出斐波那契数列每一次递归对应的递归深度。
主思想:在斐波那契数列递归基础上,因为要求调用一个递归就输出它对应的递归深度,即一个递归函数一个输出,那么就可以增加一个函数参数-depth,表示该函数的递归深度,每再函数里调用自己深度就加一:
int f(int n, int depth)
{
printf("%d\n", depth);
if(n <= 2)
return 0;
else
return f(n-1, depth+1)+f(n-2, depth+1);
}
(2)递归调试
在递归深度的基础上增加输出空格,这题主要是提供对每一层递归的图像化表示
#include <iostream>
int f_debug(int n, int depth)
{
for(int i = 0; i < 4*(depth-1); i++)
printf(" ");
printf("n=%d\n", n);
if(n <= 2)
return 1;
else
{
return f_debug(n-1, depth+1) + f_debug(n-2, depth+1);
}
}
二.🫴构造所有可行解--回溯
构造所有的可行解--->回溯,要有一个递归函数参数表示当前递归函数的递归层数/深度以进入下一层递归;要有记录当前已构造的子集temp, 且要知道当前位置🉑放的元素----->所以基础参数:F(int idx, xxx),
⚠️⚠️⚠️🎉!特别注意若temp是全局变量(即所有递归函数共用一个temp)则加入/放入后必须移除该元素!(因为要选择别的元素放置在当前位置,或是返回上一层即返回上一个位置)如果temp设定为递归函数的参数,即每个函数都有一个temp,则加入后不需移除(但最好也移除,保持代码的一致)
1、构造子集:
🌰01串
主思想: 从头开始构造,每个位置可放元素就0/1; 当前位置先放0,然后进入下一个位置(即往下递归-构造剩下的元素)删除0(先删除才能放新的元素);再放1,然后进入下一个位置,删除1,(函数结束返回上一层,即返回上一个位置)。
框架:
定义一个vector<int>temp可变长数组以存放构造中的01串; 定义一个result数组存放所有的可能01串; 定义递归函数参数为int idx以指示temp数组中当前需构造的元素。
递归边界:当idx == n,就把当前构造的01串加入result中;
构造流程:
vector<int> temp;
vector<vector<int>> result;
int n = 0;
void DFS(int idx)
{
if(idx == n)
result.push_back(temp);
else
{
temp.push_back(0);
DFS(idx+1);
temp.pop_back();
temp.push_back(1);
DFS(idx+1);
temp.pop_back();
return ;//可以去掉
}
}
难点:想清楚递归流程,如下图
知识点复习:返回值为空的函数void xxxx(xxx),执行到函数体结尾}就会自动结束函数,不需要在结尾手动编写显式return ; 除非想提前结束函数。
🎉构造子集与全排列的区别:
构造子集考虑的是当前元素即origin[idx],加入(三步:push_back, DFS(idx+1), pop_back() )与不加入(直接DFS