文章目录
题目描述
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入:s = "abc"
输出:["abc","acb","bac","bca","cab","cba"]
题解思路
递归回溯
假设s = “abc”,那么我们首先让 a 在第 0 位,再让 b 在第 0 位,再让 c 在第 0 位。
- a 在第 0 位,那么还剩 bc。我们先放 b 在第 1 位,再让 c 在第 1 位。
- b 在第 1 位,那么还剩 c。最终结果:abc。
- c 在第 1 位,那么还剩 b。最终结果:acb。
- b 在第 0 位,那么还剩 ac。我们先放 a 在第 1 位,再让 c 在第 1 位。
- a 在第 1 位,那么还剩 c。最终结果:bac。
- c 在第 1 位,那么还剩 a。最终结果:bca。
- c 在第 0 位,那么还剩 ba。我们先放 b 在第 1 位,再让 a 在第 1 位。
- b 在第 1 位,那么还剩 c。最终结果:cba。
- a 在第 1 位,那么还剩 a。最终结果:cab。
- 同时,每一次的递归我们都维护一个 haseset,用于剪枝去重(比如 s = “abb”,肯定会出现重复的排列,没有必要多去计算)。
代码实现:
class Solution {
public:
vector<string> permutation(string s) {
vector<string> res;
dfs(s, res, 0); // 从 s 的第一位开始排列起,所以传了 0
return res;
}
void dfs(string &s, vector<string> &res, int depth)
{
if(depth >= s.size()-1)
{
res.push_back(s); // 某条路从头排列到尾了,把这条路的结果输入 res
return ;
}
unordered_set<char> used; // 用于剪枝,不能定义为全局,因为每次递归需要创建一个新的 hashset
for(int i = depth; i < s.size(); ++i)
{
if(used.count(s[i])) continue; // 如果是重复的元素,不要再排一次
used.insert(s[i]);
swap(s[depth],s[i]);
dfs(s, res, depth+1); // 开始往下一层递进
swap(s[depth],s[i]); // 回溯撤销操作
}
}
};