一、概述
輸入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函數實在是太重要了。很多很好的想法都是通過它實現的。