用递归方法解决全排列问题(来自牛客网)
一、题意
给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。
我们假设对于小写字母有’a’ < ‘b’ < … < ‘y’ <‘z’,而且给定的字符串中的字母已经按照从小到大的顺序排列。
二、思路
递归的思路是把一个大的问题化解为一个一个小问题,凡是能把大的问题化解为更小问题的都可以用递归解决。
考虑能否用递归解决问题时,不要从第一个或中间某个出发考虑问题,而要从最后一个出发看待问题,从总体看待问题开始,在具体问题时常从N开始,根据题意规则演化推理到N-1,这时,N-1与N时面临相同的问题,递归由此可行了。
在确定使用递归时,主要有两个关键点:
- N与N-1的关系。类似数列递推式,不必知道N和N-1的的具体取值情况,知道N与N-1的关系式就能从一开始推到N;
- 递归出口。经常为N=1或N=0时,所求结果的取值,类比数列赋初值。
在进行实际编程时,面临的问题根据所求的结果常分为两类:
- 所求结果为第N问题的结果,即中间某过程的结果不需要保留,如汉诺塔求移动次数问题,这样的问题往往不需要不需要模拟具体操作,自己推理出递推关系,直接编程即可。
- 所求结果要求保留中间每个过程的结果。这时,一般要模拟题意进行操作,记录每次迭代的结果,如全排列问题,要求记录每次迭代的字母并输出。
三、代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int b[6];//标记
int n;
char s[6];//原字符串
char res[6];//存结果
void A(int cnt)
{
if(cnt ==n-1)//递归出口
{
for(int j=0;j<n;j++)
{
if(b[j]==0)
{
res[cnt]=s[j];
printf("%s\n",res);
}
}
}
else {
for(int j=0;j<n;j++)
{
if(b[j]==0)
{
b[j]=1;
res[cnt]=s[j];
A(cnt+1);//不能用cnt++或++cnt,迭代回来时会出错
b[j]=0;
}
}
}
}
int cmp(const void *a,const void *b)
{
return *(char *)a-*(char *)b;
}
int main()
{
memset(b,0,sizeof(b));
while(scanf("%s",s)!=EOF)
{
n=strlen(s);
int cnt =0;//计数
qsort(s,n,sizeof(s[0]),cmp);//排序
if(n==1)
printf("%s\n",s);
for(int i=0;i<n;i++)
{ cnt =0;
b[i]=1;
res[cnt]=s[i];
A(cnt+1);
b[i]=0;
}
printf("\n");
memset(s,0,sizeof(s));
}
}
四、结果
五、易错点
- printf函数要放在递归出口;
- 用全局变量数组迭代时没有字符串连接的麻烦;