题目描述:
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 结果请按字母顺序输出。
输入要求:输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
思考:
感觉难度挺大的,首先是解决全排列的问题,而且可能含有重复元素,还要按顺序打印。
因为是按顺序打印,所以想到应该先把输入串按升序排序,调用sort()直接实现,然后就是一个个去找下一个全排列并输出。
但是如何找下一个全排列?
自己先尝试写,未果,网上查到了STL中有next_permutation的算法正是实现这个功能,果然在《STL源码剖析》中找到实现代码:
template<class BidirectionalIterator>
bool next_permutation(
BidirectionalIterator first,
BidirectionalIterator last
)
{
if(first == last)
return false; //空区间
BidirectionalIterator i = first;
++i;
if(i == last)
return false; //只有一个元素
i = last;// i指向尾端
--i;
for(;;) {
BidirectionalIterator ii = i;
--i;
//锁定两个相邻元素
if(*i < *ii) { //如果前一个元素小于后一个元素
BidirectionalIterator j = last; //j指向尾端
while(!(*i < *--j)); //j从后向前,直到找到比*i大的元素*j
iter_swap(i, j); //交换i,j
reverse(ii, last); //将ii及其之后的元素逆序
return true;
}
if(i == first) { //到首位也没找到,说明完全倒序。
reverse(first, last); //所有元素逆序,及变为完全正序。
return false;
}
}
}
这算法是怎样的实现思路呢?
假如有(......1S2)这样的排列,其中S是一个非递减字符串(如6543),求它的下一个排列,1是从尾部向前遍历的第一个小于2的数,那么就把1和2交换,然后把交换后2的后面的序列(65431)逆序,得到......213456。这是普遍情况下的思路,其它情款类似。
根据标记从后往前比较相邻两数据,若前者小于(默认为小于)后者,标志前者为X1(位置PX)表示将被替换,再次重后往前搜索第一个不小于X1的数据,标记为X2。交换X1,X2,然后把[PX+1,last)标记范围置逆。完成。
AC的代码:
vector<string> Permutation(string str) {
vector<string> res;
if(str.empty())
return res;
sort(str.begin(),str.end());
do{
res.push_back(str);
}
while(next_permutation(str.begin(),str.end()));
return res;
}