ACwing842.全排列
先引入这个全排列理解一下如何递归和回溯的(可以在本子上画画,或者一步步调试看看)
题目描述(来源ACwing):
思路:1 2 3全排列,我们肯定会怎么排1 2 3,1 3 2,2 1 3,2 3 1,3 1 2,3 2 1,其实写成代码就是一个回溯的过程,1 2 3全部排完我们就输出,然后回退到1 2,三已经选过,再回退到1,此时2 也已经选过,我们选3,然后选2,1 3 2排完我们再输出再继续回溯,一回到数组全部遍历结束并且此时已经全部选过,那我们既要有一个数组来标记当前元素是否已被选择过,回溯的过程要将该元素的标记取出以参与下一次排列
代码实现C++:
#include<iostream>
using namespace std;
const int N=10;
int p[N],st[N];
int n;
void dfs(int x){
if(x==n){//当x==n说明当前数组里已经有n个元素了,直接输出然后return即回溯
for(int i=0;i<n;i++){
cout<<p[i]<<" ";
}
cout<<endl;
return;
}
for(int i=1;i<=n;i++){
if(!st[i]){//该元素没有被标记,那就加入当前数组并修改标记
p[x]=i;
st[i]=true;
dfs(x+1);
st[i]=false;
}
}
}
int main()
{
cin>>n;
dfs(0);
return;
}
LeetCode46.全排列(dfs+回溯)
题目描述(来源LeetCode):
有是开启回溯的一天,我似乎还是没有掌握到精髓,这个题又做了半个小时,我做的时候,我觉得难点可能就是递归函数的参数问题,(纠结了老半天)然后想到了之前做的一个全排列,从1~n的全排列,其实递归的出口就是当前数组里有n个元素了,说明本次搜索结束,开始回溯
思路:递归+回溯,首先递归的结束条件:当前数组的元素个数等于题目给出的数组的元素个数,则这就是一组可行解。其他情况,我们每次都要考虑当前位置应该填什么,那就要遍历题目给出的数组,肯定不能填目前数组里已经存在的,那怎么判断存不存在,就可以用一个st数组来标记当前元素是否已被填入,如果没有被标记st[i]=false,我们就将该元素填入并从数组的下一个位置继续递归,如果被标记过了,那就继续遍历题目所给数组即可
代码实现C++:
class Solution {
public:
vector<int> num;
vector<vector<int>> res;
vector<bool> st;
vector<vector<int>> permute(vector<int>& nums) {
if(nums.size()==0) return res;
st.resize(nums.size(), false);
dfs(nums);
return res;
}
void dfs(vector<int>& nums){
if(num.size()==nums.size()){//当前数组里的元素个数等于题目数组的元素个数的时候,说明本次搜索结束,开始回溯
res.push_back(num);//将当前数组加入答案当中去
return;
}
for(int i=0;i<nums.size();i++){//遍历题目所给的数组
if(!st[i]){//如果该元素没有被标记就将该元素加入数组并修改标记
num.push_back(nums[i]);
st[i]=true;
dfs(nums);
st[i]=false;//回溯的过程要修改标记
num.pop_back();
}
}
}
};
其实可以发现,回溯的题,在递归的前后代码一般是对称的哦!
1.递归结束的条件,2.对什么进行回溯,3从哪里开始
今日刷题任务完成,希望下次遇到回溯可以快点写出。明天见~(欢迎留言交流呀!)