一、概述
输入n个元素,找其全排列 。
第一眼看上去有点懵,然后就开始DFS。用unordered_set当哈希表来记录当前序列已经有的值,然后遍历剩余的值。
想法特别简单,时空复杂度还好。
但是这方法明显不好——肯定不是最优解。
最优解没有用set,使用很多次的swap实现的。
二、分析
1、我的方法
直接深搜,每在序列中加入一个元素,就把这个元素加入set,最后将序列加入结果中。代码如下:
class Solution {
vector<vector<int> > res;
unordered_set<int> s;
void DFS(vector<int>& tmp,int now,int n,vector<int>& nums)
{
if(now==n)
{
res.push_back(tmp);
return;
}
else
{
for(int i=0;i<n;++i)
{
if(s.find(nums[i])==s.end())
{
s.insert(nums[i]);
tmp.push_back(nums[i]);
DFS(tmp,now+1,n,nums);
tmp.pop_back();
s.erase(nums[i]);
}
}
}
}
public:
vector<vector<int>> permute(vector<int>& nums) {
int n=nums.size();
vector<int> tmp;
DFS(tmp,0,n,nums);
return res;
}
};
很直白,容易想到,但是效率不高。
2、较好的方法
我们以输入1、2、3、4为例,输出可以是:
1、2、3、4
4、3
3、2、4
4、2
4、2、3
3、2
这样1开头的就完事了。观察我写序列的这个顺序,第一个和第二个是1、2、3、4和1、2、4、3,最后两个调换位置。之后是1、3、2、4,从1、2系列改成了1、3系列,可以看做2、3调换位置。然后继续最后两个调换位置。接下来1、2变成1、4可以看成3、2调换位置。说明本质上,序列的生成就是一系列调换位置的结果。比如说上面六个序列的生成:
1不动,2和2换,3和3换;
1不动,2和2换,3和4换;
1不动,2和3换,2和2换;
1不动,2和3换,2和4换;
1不动,2和4换,2和2换;
1不动,2和4换,2和3换;
就相当于第一次调换为2和2、3、4换,第二次调换也一样。
整体来看,第一次相当于1和1换,之后1和2、3、4换,生成所有序列。
这也是DFS。但是比我的好多了。如下:
class Solution {
vector<vector<int> > res;
void DFS(int now,int n,vector<int>& nums)
{
if(now==n)
{
res.push_back(nums);
return;
}
else
{
for(int i=now;i<n;++i)
{
swap(nums[now],nums[i]);
DFS(now+1,n,nums);
swap(nums[i],nums[now]);
}
}
}
public:
vector<vector<int>> permute(vector<int>& nums) {
int n=nums.size();
vector<int> tmp;
DFS(0,n,nums);
return res;
}
};
三、总结
序列处理中,这个swap函数实在是太重要了。很多很好的想法都是通过它实现的。