题目
题目源自leetcode这三道题
leetcode-46
leetcode-47
leetcode-267
思路1:唯一全排列
这里总结下上述问题的思路。假设给定一个数组,里面的数字均唯一。比如[1, 2, 3, 4, 5, 6]如何做出他们的全排列。这里我们的思路有很多个解释。
1. 直觉法
根据直觉我们知道。我们可以在第一个位置上,从6个数字中任选一个。然后在第二个位置从5个中选一个。结果就是6 * 5 * 4 * 3 * 2 * 1
这里迭代的顺序是位置。从第一个位置一直到最后一个位置。当到达最后一个位置的时候,这时这个排列就可以加入到结果集中。
code
这里的代码和思路之间的连接需要打通一下。
- 当我们从所有的数字选定第一个位置时,我们仅仅是用swap将其到第一个位置。注意每个数字都有被选中的可能。所以是从start开始,到最后结束。
- 当选定第一个位置后。第二位置选时,我们要让start+1, 来代表我们要选择第二个数字。
- 最后确定递归的结束点。即选定最后一个元素完毕之后,此时index恰好是size大小。代表我们已经做出一个全排列,然后将其加入到我们的结果集合中。
void backtrack(vector<int> ivec, int start, vector<vector<int>> &res);
vector<vector<int>> permute(vector<int> ivec){
vector<vector<int>> res;
backtrack(ivec, 0, res);
return res;
}
void backtrack(vector<int> ivec, int start, vector<vector<int>> &res){
if(start == ivec.size()){
res.push_back(ivec);
return;
}
for(int i = start; i < ivec.size(); i++){
swap(ivec[start], ivec[i]);
backtrack(ivec, start + 1, res);
swap(ivec[start], ivec[i]);
}
}
int main(){
vector<int> ivec{1, 2, 3};
auto res = permute(ivec);
for(auto elem_vec : res){
for(auto elem : elem_vec)
cout << elem << "\t";
cout << endl;
}
}
2. 分治
从分治的角度去思考这个问题。当我们知道前i个数字的位置后。剩下的total-i个可以化解成为更小的全排列问题。
仔细想想这个思路的过程。我们需要一个set来记录当前剩下的数字。
- 一个for循环
- 从set中选取一个数字。然后利用func(set)得到剩下数组的全排列。
- 将当前数字和剩下数组的全排列组成新的全排列。
- 然后返回所有的全排列。
用分治的方法来做有点麻烦。
用当前数字和全排列的组合来组成新的全排列需要将当前数字分别插入全排列中的每个vec的各种可能位置。
code
这里的思路就是当前从set中选定一个数字之后。然后让剩下的数字组成全排列。然后让当前数字和全排列再次组合成全新的全排列。因此里面含有大量的插入,选用list更加合适一些。
#include <iostream>
#include <vector>
#include <set>
using namespace std;
set<vector<int>> func(set<int> hashset, int x, bool flag);
vector<vector<int>> permute(vector<int> ivec){
set<int> hashset(ivec.begin(), ivec.end());
auto res_set = func(hashset, 0, false);
vector<vector<int>> res_vec;
for(auto each_vec : res_set){
res_vec.push_back(each_vec);
}
return res_vec;
}
set<vector<int>> func(set<int> hashset, int x, bool flag){
if(flag){
hashset.erase(x);
}
set<vector<int>> res;
for(auto elem : hashset){
int curr = elem;
auto tmp = func(hashset, curr, true);
if(tmp.empty()){
vector<int> ivec{curr};
res.insert(ivec);
}else{
for(auto each_vec : tmp){
for(int j = 0; j <= each_vec.size(); j++){
vector<int> ivec = each_vec;
ivec.insert(ivec.begin()+j, curr);
res.insert(ivec);
}
}
}
}
return res;
}
int main(){
vector<int> ivec{1, 2, 3};
auto res = permute(ivec);
for(auto elem_vec : res){
for(auto elem : elem_vec)
cout << elem << "\t";
cout << endl;
}
}
思路2:不唯一
当数组中给定的数字不再唯一之后,有一点小小的变数。
- 最简单的方法就是直接选用一个set来作为结果集,可以直接帮忙去重。