vector<string> ans;
void dfs(string input,string path){
if(input.size() == 0){
//到达目标状态
ans.push_back(path);
} else{
//将input中的每一个字母作为第一个字符试一下
for(int i = 0; i < input.size();i++){
//不为目标状态,减少字符串最后的一个字符
string curPath = path;
curPath += input[i];
string subtr = input.substr(0,i) + input.substr(i+1);
dfs(subtr,curPath);
}
}
}
int main(){
string input;
while(cin >> input){
dfs(input,"");
for(auto ele: ans){
cout<<":"<<ele<<endl;
}
}
return 0;
} 使用递归
void pailie(char *str ,char *start) { if(str== NULL || start==NULL) { return ; } if(*start == '\0') { printf("%c\n",str); } else { char *pch; char tmp; for(pch = start ; pch != '\0' ;pch++) { tmp = *pch; *pch = *start; *start = tmp;
pailie(str , start+1); tmp = *pch ; *pch = *start; *start = tmp; } } } void main() { char *str="abc"; char *start = str; pailie(str ,str); }
题目描述
输入一个字符串,打印出该字符串中字符的所有排列。
例如输入字符串abc,则输出由字符a、b、c 所能排列出来的所有字符串
abc、acb、bac、bca、cab 和 cba。
分析与解法
解法一、递归实现
从集合中依次选出每一个元素,作为排列的第一个元素,然后对剩余的元素进行全排列,如此递归处理,从而得到所有元素的全排列。以对字符串abc进行全排列为例,我们可以这么做:以abc为例
void CalcAllPermutation(char* perm, int from, int to) { if (to <= 1) { return; //递归出口 } if (from == to) //输出条件 { for (int i = 0; i <= to; i++) cout << perm[i]; cout << endl; } else { for (int j = from; j <= to; j++) { swap(perm[j], perm[from]); //关键 CalcAllPermutation(perm, from + 1, to); swap(perm[j], perm[from]); } } }解法二、字典序排列
首先,咱们得清楚什么是字典序。根据维基百科的定义:给定两个偏序集A和B,(a,b)和(a′,b′)属于笛卡尔集 A × B,则字典序定义为
(a,b) ≤ (a′,b′) 当且仅当 a < a′ 或 (a = a′ 且 b ≤ b′)。
所以给定两个字符串,逐个字符比较,那么先出现较小字符的那个串字典顺序小,如果字符一直相等,较短的串字典顺序小。例如:abc < abcd < abde < afab。
那有没有这样的算法,使得
答案是肯定的:有,即是STL中的next_permutation算法。
在了解next_permutation算法是怎么一个过程之前,咱们得先来分析下“下一个排列”的性质。
现在的问题是:找到x和y。怎么找到呢?咱们来看一个例子。
比如说,现在我们要找21543的下一个排列,我们可以从左至右逐个扫描每个数,看哪个能增大(至于如何判定能增大,是根据如果一个数右面有比它大的数存在,那么这个数就能增大),我们可以看到最后一个能增大的数是:x = 1。
而1应该增大到多少?1能增大到它右面比它大的那一系列数中最小的那个数,即:y = 3,故此时21543的下一个排列应该变为23xxx,显然 xxx(对应之前的B’)应由小到大排,于是我们最终找到比“21543”大,但字典顺序尽量小的23145,找到的23145刚好比21543大。
由这个例子可以得出next_permutation算法流程为:
next_permutation算法
定义
步骤(二找、一交换、一翻转)
还是拿上面的21543举例,那么,应用next_permutation算法的过程如下:
bool CalcAllPermutation(char* perm, int num){ int i; //①找到排列中最后(最右)一个升序的首位位置i,x = ai for (i = num - 2; (i >= 0) && (perm[i] >= perm[i + 1]); --i){ ; } // 已经找到所有排列 if (i < 0){ return false; } int k; //②找到排列中第i位右边最后一个比ai 大的位置j,y = aj for (k = num - 1; (k > i) && (perm[k] <= perm[i]); --k){ ; } //③交换x,y swap(perm[i], perm[k]); //④把第(i+ 1)位到最后的部分翻转 reverse(perm + i + 1, perm + num); return true; }然后在主函数里循环判断和调用calcAllPermutation函数输出全排列即可。
解法总结