题目描述
从提交结果可以看到此算法效率是很高的,虽然效率高,但递归算法还是有点难理解,我给大家口述一下代码逻辑。第一次调用函数perm时算法正式开始,此perm函数只有一个if…else…结构,if就是递归函数的出口,而else就是进行递归的部分,主要是用到了分治的思想。
算法思想:
以不重复元素1,2,3为例为大家讲解算法
首先for循环区间为1,2,3,perm中的for循环开始
nums[i]和nums[low]交换位置,此时i与low相等,自己和自己交换位置。接着进入第二层递归,for循环区间为2,3,图如下
nums[i]和nums[low]交换位置,此时i与low相等,自己和自己交换位置。接着进入第三层递归,for循环区间为3,图如下
此时low==high,进入if,保存此时的数组nums(即1,2,3),第三层递归执行到函数尾部,返回调用处。即上一层的perm(nums, 2, 2);。
接着执行nums[1]和nums[2] 交换位置(即还原数组操作),此时也是自己和自己交换,然后进入下一轮for循环,执行i++(图中已完成),然后nums[low]和nums[i] 交换位置,得到如下的数组
接着进行下一层递归,perm(nums, low+1, high),即perm(nums, 2, 2)
此时low==high,进入if,保存此时的数组nums(即1,3,2),第三层递归执行到函数尾部,返回调用处。即上一层的perm(nums, 2, 2);,接着执行交换操作swap(nums[1], nums[2]),将数组还原(变成序列1,2,3)。else语句执行完成后到达函数尾,再返回到调用处perm(nums, 1, 2),执行交换操作后 i++ 进行下一轮for循环
至此,元素1放在0号位置结束,执行swap(nums[low], nums[1]),将数组变成2,1,3,此时元素2放在0号位置,开始新一轮的递归
提示:看代码只看perm函数即可,不用把递归理解的很复杂,此函数只有一个if…else…结构
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
vector<vector<int> > res;
//检查是否已经遍历过重复元素
bool isSwap(vector<int>& nums, int low, int high){
for(int i=low; i<high; i++){
if(nums[high] == nums[i]){
return false;
}
}
return true;
}
void perm(vector<int>& nums, int low, int high){
//递归分治到最后,只剩下了最后一个元素,将此时的数组保存即可
if(low == high){
res.push_back(nums);
}else{
//检查在i遍历过的区间[low,i-1]中是否出现过此时正要交换的nums[i]
//若已经遍历过与此时的nums[i]相等的元素
//则不用交换起始元素nums[low]和当前元素nums[i],跳过本次循环
for(int i=low; i<=high; i++){
if( isSwap(nums, low, i) ){
swap(nums[low], nums[i]);
perm(nums, low+1, high);
swap(nums[low], nums[i]);
}
}
}
}
vector<vector<int> > permuteUnique(vector<int>& nums) {
perm(nums, 0, nums.size()-1);
return res;
}
int main(){
vector<int> nums;
nums.push_back(1);
nums.push_back(2);
nums.push_back(2);
nums.push_back(3);
vector<vector<int> > res = permuteUnique(nums);
for(int i=0; i<res.size(); i++){
for(int j=0; j<res[i].size(); j++){
cout<<res[i][j]<<" ";
}
cout<<"\t";
}
return 0;
}
本地运行结果:
线上提交结果:
总结:
递归算法确实不太好讲,也不容易理解。但是一定要把握住大的方向,那就是所有元素都有机会放在循环区间的首位置(即代码中的swap(nums[low],nums[i]),low表示此时区间的首位置),将剩余元素进行全排列。一层一层递归分治的时候,for循环区间不断减小,当区间内元素只剩一个时(即low==high),输出保存此时的数组。