题目
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入:s = “abc”
输出:[“abc”,“acb”,“bac”,“bca”,“cab”,“cba”]
限制:
1 <= s 的长度 <= 8
分析
1.因为题目所给数组存在重复,并且要求结果去重所以选set保存,最后返回的时候返回vector
2.算法核心其实就是dfs也可以说是回溯法
3.因为有set可以保证没有重复所以每次交换后需要重新恢复位置
4.为了提高效率相邻字符如果相同,则跳过。其实主要是固定一部分,然后与其他字符进行交换
#include<vector>
#include<string>
#include<set>
using namespace std;
class MyClass
{
public:
vector<string> permutation(string s){
set<string> res;
permutation(res, s, 0);
return vector<string>(res.begin(),res.end());
}
void permutation(set<string>& res, string s, int pos){
if (pos == s.size() - 1){
res.insert(s);
return;
}
for (int i = pos; i < s.size(); ++i){
if (i != pos && s[i] == s[pos]){
continue;
}
swap(s[i], s[pos]);
permutation(res, s, pos + 1);
swap(s[i], s[pos]);
}
}
};
下面是网上看到的另一种方式;
std::vector<std::string> permutation(std::string s) {
if(s.empty()){
return {};
}
// 对字符串进行排序
std::sort(s.begin(), s.end());
std::vector<std::string> res;
// 标记字符是否遍历过
std::vector<bool> visit(s.size(), false);
std::string track;
backtrack(res, s, track, visit);
return res;
}
* 回溯函数
* 使用sort函数对字符串排序,使重复的字符相邻,
* 使用visit数组记录遍历决策树时每个节点的状态,
* 节点未遍历且相邻字符不是重复字符时,
* 则将该字符加入排列字符串中,依次递归遍历。
* *
void backtrack(std::vector<std::string> &res, std::string s, std::string &track, std::vector<bool> &visit) {
// 回溯结束条件
if (track.size() == s.size()){
res.push_back(track);
return;
}
// 选择和选择列表
for (int i = 0; i < s.size(); i++){
// 排除不合法的选择
if (visit[i]){
continue;
}
if (i > 0 && !visit[i - 1] && s[i - 1] == s[i]){
continue;
}
visit[i] = true;
// 做选择
track.push_back(s[i]);
// 进入下一次决策树
backtrack(res, s, track, visit);
// 撤销选择
track.pop_back();
visit[i] = false;
}
}