题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
这道题是剑指offfer中一道经典的题,如果有n个元素,我们就能有n*(n - 1)个全排列,n为1时,只有一个全排列
举个栗子,当字符串为ABC时,分析一下全排列的过程:
1.固定A在字符串的最左边,然后全排列B和C
2.全排列B和C
3.当全排列的字符串只有一个字符时,它的全排列就是它自身
4.当固定A后,其他字符串的全排列完毕后,把A与其他字符进行交换,然后重复上面的步骤进行全排列
示意图如下:
基于这种思路,我使用回溯法解决,代码如下:
class Solution {
public:
vector<string> Permutation(string str) {
vector<string> ret;
if (str.empty()) {
return ret;
}
string tmp = "";
_permutation(str, ret, tmp, 0);
return ret;
}
private:
void _permutation(string str, vector<string>& ret, string& tmp, int begin) {
if (begin == str.size()) {
ret.push_back(tmp);
return;
}
for (int i = begin; i < str.size(); ++i) {
if (i != begin && str[i] == str[begin])
continue;
swap(str[i], str[begin]);
tmp += str[begin];
_permutation(str, ret, tmp, begin + 1);
tmp.pop_back();
}
}
};
这里主要解释一下这个函数:
void _permutation(string str, vector<string>& ret, string& tmp, int begin) {
if (begin == str.size()) {
ret.push_back(tmp);
return;
}
for (int i = begin; i < str.size(); ++i) {
if (i != begin && str[i] == str[begin])
continue;
swap(str[i], str[begin]);
tmp += str[begin];
_permutation(str, ret, tmp, begin + 1);
tmp.pop_back();
}
}
这个函数的思路就是上面的思路,使用回溯法,思路如下
1. 让当前字符去和每个字符串交换
2.交换完成后,递归的调用函数去处理除当前字符之外剩下的字符
递归的出口就是begin等于str.size(),这时候的tmp(因为一直在保存每一个字符),就是一个全排列的结果,保存在数组ret之中
注意,在循环中有这么一个判断:
if (i != begin && str[i] == str[begin])
continue;
这个判断主要是处理字符串中有重复字符的
去重的全排列就是从第一个数字起,每个数分别与它后面非重复出现的数字交换
在这个循环遍历时,有两种情况str[i]和str[begin]相等,一种是i和begin相等,即同一个元素,一种是相同的元素
这时候如果交换的话没有意义,就不用交换并且保存了,不然就会出现重复的结果
举个栗子,当字符串为aabb时,如果注释掉这句话,ret的结果是
如果不注释掉,结果是正确的:
如果要按照字典序输出的话,还需要对数组ret进行排序
再介绍一种简单的方法,如果为了快速AC的话,可以使用STL中的next_permutation函数,函数定义如下:
template <class BidirectionalIterator>
bool next_permutation (BidirectionalIterator first,
BidirectionalIterator last);
template <class BidirectionalIterator, class Compare>
bool next_permutation (BidirectionalIterator first,
BidirectionalIterator last, Compare comp);
解决的代码如下:
vector<string> Permutation(string str) {
vector<string> answer;
if(str.empty())
return answer;
sort(str.begin(),str.end());
do{
answer.push_back(str);
}
while(next_permutation(str.begin(),str.end()));
return answer;
}
这个函数的文档链接如下:
http://www.cplusplus.com/reference/algorithm/next_permutation/?kw=next_permutation
---------------------
作者:Qregi
来源:CSDN
原文:https://blog.csdn.net/Qregi/article/details/82049298
版权声明:本文为博主原创文章,转载请附上博文链接!