文章目录
1.字符串的排列–回溯(去重
题目描述:
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
难度:中等
字符串的排列
题解:
贴一版比较容易想到的,直接在常规的排列的代码上加入hash实现去重的代码。
class Solution {
vector<string> ans;
unordered_set<string> set;
public:
void backtracking(string s,int step){
if(step==s.size()){
if(set.count(s)==0){
set.insert(s);
ans.push_back(s);
}
return;
}
for(int i=step;i<s.size();i++){
swap(s[step],s[i]);
backtracking(s,step+1);
swap(s[step],s[i]);
}
}
vector<string> permutation(string s) {
backtracking(s,0);
return ans;
}
};
再来一版剪枝的。
我的理解:交换元素的操作,实际上就是选一个还没有选过的数,放到当前的位置上,那么用一个set记录当前位置上都选过哪些数了,如果发现选到了重复的数,那么直接剪枝,之后的位置也不用再选了,因为肯定跟前面重复了。具体看代码注释。
class Solution {
public:
vector<string> permutation(string s) {
dfs(s, 0);
return res;
}
private:
vector<string> res;
void dfs(string s, int x) {
if(x == s.size() - 1) {
res.push_back(s); // 添加排列方案
return;
}
set<int> st;
for(int i = x; i < s.size(); i++) {
if(st.find(s[i]) != st.end()) continue; // 重复,因此剪枝
st.insert(s[i]);
swap(s[i], s[x]); // 交换,将 s[i] 固定在第 x 位
dfs(s, x + 1); // 开启固定第 x + 1 位字符
swap(s[i], s[x]); // 恢复交换
}
}
};
作者:jyd
链接:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof/solution/mian-shi-ti-38-zi-fu-chuan-de-pai-lie-hui-su-fa-by/
下面题解来自官方
先对s排序,保证相同的字符相邻,在递归函数中,限制每次填入的字符一定是这个字符所在重复字符集合中「从左往右第一个未被填入的字符」。
class Solution {
public:
vector<string> rec;
vector<int> vis;
void backtrack(const string& s, int i, int n, string& perm) {
if (i == n) {
rec.push_back(perm);
return;
}
for (int j = 0; j < n; j++) {
if (vis[j] || (j > 0 && !vis[j - 1] && s[j - 1] == s[j])) {
continue;
}//去重
vis[j] = true;
perm.push_back(s[j]);
backtrack(s, i + 1, n, perm);
perm.pop_back();
vis[j] = false;
}
}
vector<string> permutation(string s) {
int n = s.size();
vis.resize(n);
sort(s.begin(), s.end());
string perm;
backtrack(s, 0, n, perm);
return rec;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof/solution/zi-fu-chuan-de-pai-lie-by-leetcode-solut-hhvs/