剑指 Offer 38. 字符串的排列 - 力扣(LeetCode)
题目的意思是字符串里的字符可以是重复的,而输出结果不能重复。
那就是回溯就可以了,建立一个访问数组记录哪些元素已经被添加过,最后使用哈希表自动去重。
class Solution {
public:
unordered_set<string> res;
vector<int> visited;
string tmp;
vector<string> permutation(string s) {
visited = vector<int>(s.size(), 0);
backtrack(s);
return vector<string>(res.begin(), res.end());
}
void backtrack(string &s){
if(tmp.size() == s.size()){
res.insert(tmp);
return;
}
for(int i = 0; i < s.size(); ++i){
if(visited[i] == 0){
tmp += s[i];
visited[i] = 1;
backtrack(s);
tmp.pop_back();
visited[i] = 0;
}else continue;
}
}
};
当然不用访问数组也是可以的:
class Solution {
public:
unordered_set<string> res;
string tmp;
vector<string> permutation(string s) {
backtrack(s);
return vector<string>(res.begin(), res.end());
}
void backtrack(string &s){
if(tmp.size() == s.size()){
res.insert(tmp);
return;
}
for(int i = 0; i < s.size(); ++i){
if(s[i] == '#') continue;
else{
char ch = s[i];
tmp += s[i];
s[i] = '#';//打上已被选取的标记
backtrack(s);
tmp.pop_back();
s[i] = ch;//恢复
}
}
}
};
可以先排序,然后再进行回溯,效率会更高:
class Solution {
public:
vector<string> res;
string tmp;
vector<string> permutation(string s) {
sort(s.begin(), s.end());
backtrrack(s);
return res;
}
void backtrrack(string &s){
if(tmp.size() == s.size()){
res.emplace_back(tmp);
//cout << tmp << endl;
return;
}
for(int i = 0; i < s.size(); ++i){
//这儿要注意我们遍历到下一层的i的时候,上一层i前面的字符已经修改为'_'了
//这儿的去重逻辑仔细想想,不太好理解的(注意字符的修改与还原)
if(s[i] == '_' || (i > 0 && s[i] == s[i-1])) continue;
char c = s[i];
tmp += s[i];
s[i] = '_';
backtrrack(s);
tmp.pop_back();
s[i] = c;
}
}
};