LeetCode 面试题 08.08. 有重复字符串的排列组合
解法一:
class Solution {
public:
vector<string> permutation(const string& S) {
int len = S.length();
set<string> strs;
vector<vector<char>> perms = permute(vector<char>(S.begin(), S.end()));
for (auto& i : perms) {
strs.insert(string(i.begin(), i.end()));
}
return vector<string>(strs.begin(), strs.end());
}
private:
template <class T>
vector<T> rotate_imp(const vector<T>& nums, int n) {
vector<T> ret;
int sz = (int)nums.size();
for (int i = 0; i < sz; ++i) {
ret.emplace_back(nums[(i + n) % sz]);
}
return ret;
}
template <class T>
vector<vector<T>> rotate(const vector<vector<T>>& per) {
vector<vector<T>> ret;
for (auto& i : per) {
for (int j = 0; j < i.size(); ++j) {
ret.emplace_back(rotate_imp(i, j));
}
}
return ret;
}
template <class T>
vector<vector<T>> permute(const vector<T>& nums) {
vector<vector<T>> ret{{}};
for (auto& i : nums) {
for (auto& j : ret) j.emplace_back(i);
ret = rotate(ret);
}
return ret;
}
};
解法二:
class Solution {
public:
vector<string> permutation(string& S) {
backtrack(S);
return rst;
}
private:
void backtrack(string& S, int start = 0) {
int len = (int)S.length();
if (len == start) {
rst.emplace_back(S);
return;
}
set<char> vis;
for (int i = start; i < len; ++i) {
if (vis.find(S[i]) == vis.end()) {
vis.insert(S[i]);
swap(S[i], S[start]);
backtrack(S, start + 1);
swap(S[i], S[start]);
}
}
}
private:
vector<string> rst;
};
解题思路
难点1:全排列的题,归根揪底,需要手动实现permute,无非两种实现方式,一种是使用递归进行回溯,另一种是直接for循环进行轮换;
难点2:解法一使用轮换实现了全排列的基础算法,做成了模板函数进行使用;set去重即可;
难点3:解法二使用的回溯+剪枝,使用set进行剪枝去重;回溯的话,掌握回溯的基本结构即可灵活运用;
难点4:总的来讲,这道题不掌握套路,直接上手撸还是蛮难的;
知识点:
知识点1:STL中next_permutation的用法(自动去重,用前需要进行排序);
class Solution {
public:
vector<string> permutation(string S) {
vector<string> res;
string path;
sort(S.begin(), S.end());
do{
for(int i = 0; i < S.size(); i++){
path += S[i];
}
res.push_back(path);
path = {};
}while(next_permutation(S.begin(), S.end()));
return res;
}
};
知识点2:回溯算法的基本框架;参考回溯算法详解;
// result = []
// def backtrack(路径, 选择列表):
// if 满足结束条件:
// result.add(路径)
// return
// for 选择 in 选择列表:
// 做选择
// backtrack(路径, 选择列表)
// 撤销选择