题目描述:
输入一个字符串,按字典序打印出该字符串中字符的所有排列。
例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
题目分析:
如下图,第一种情况(ABB)是存在字符重复时,全排列出现重复的例子。
第二种情况(ABC)是不存在字符串重复时的情况,全排列的例子。
因为第二种情况更加明显,因为以不存在重复时进行说明算法的思路。
首先看与ABC相连的(A、B、C),实际上可以看作后面的字符与第一个字符(A)的交换,此时第一个字符的位置相当于被固定。
然后是第二个位置进行固定。。。依次直到最后一个位置被固定。由于需要排除掉重复的字符串,因为还需要使用unordered_set进行去重,代码中以set表示。
详细代码如下
class Solution {
public:
//递归
set<string> st;
//pos表示下标(每次被固定位置),从0开始,到字符串str结束位置结束。
void dfs(string str,int pos){
//递归终止的条件
if(pos==str.size()-1){
st.insert(str);
return;
}
for(int i=0;i<str.size();i++){
//将后面的字符依次与被固定位置进行交换
// for循环和swap的含义:对于“ABC”,
// 第一次'A' 与 'A'交换,字符串为"ABC", pos为0, 相当于固定'A'
// 第二次'A' 与 'B'交换,字符串为"BAC", pos为0, 相当于固定'B'
// 第三次'A' 与 'C'交换,字符串为"CBA", pos为0, 相当于固定'C'
swap(str[pos],str[i]);
dfs(str,pos+1);
//回溯,还原交换之前的样子
// 回溯的原因:比如第二次交换后是"BAC",需要回溯到"ABC"
// 然后进行第三次交换,才能得到"CBA"
swap(str[pos],str[i]);
}
}
vector<string> Permutation(string str) {
if(str.empty())return {};
dfs(str,0);
//返回一个使用头迭代器和尾迭代器初始化的向量
return vector<string>({st.begin(),st.end()});
}
};