【题目描述】
给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。
我们假设对于小写字母有‘a’ <‘b’ < ... <‘y’<‘z’,而且给定的字符串中的字母已经按照从小到大的顺序排列。
【输入】
只有一行,是一个由不同的小写字母组成的字符串,已知字符串的长度在1到6之间。
【输出】
输出这个字符串的所有排列方式,每行一个排列。要求字母序比较小的排列在前面。字母序如下定义:
已知S = s1s2…sk , T = t1t2…tk,则S < T 等价于,存在p (1 <= p <= k),使得s1 = t1, s2 = t2, …, sp - 1 = tp - 1, sp < tp成立。
【输入样例】
abc
【输出样例】
abc acb bac bca cab cba
【解题思路】
按照字典序输出某个字符串的全部排列其实带有很深的递归思想。
以题目中的abc为例:
对于第一位(从左到右)字母来说,它就是abc字符串中字母的字典序排列;
对于第二位字母来说,就是将第一位的字母除去后的剩下的字母的字典序排列。
对于第三位字母来说,就是除去前两位字母后的字典序排列。当然,由于本例中只有三个字母,因此最后一位字母在前两位确定之后也就确定了,因此不符合这个条件。
不难看出,除最后一位之外,之前的每一位在纵向上都是排除了其前面位字母后的字典序排列。因此我们就得到了基本的解题思路:
根据字母的位数不同分层,每层按照字典序进行进行一次遍历。每往下一层就去除前一位的字母。比如在本例中第一层遍历abc,第二层遍历bc,第三层直接输出。
【代码】
#include<iostream>
#include<string.h>
using namespace std;
char a[10],b[10];//将a字符串的各种排列依次放到b字符串中
int vis[10]={0},n;//用vis[i]来代表a[i]字母有没有被访问过
void dfs(int k){
if(k==n){
cout<<b<<endl;
}
for(int i=0;i<n;i++)
if(vis[i]==0){
b[k]=a[i]; //没有访问过就放到b数组中
vis[i]=1; //作上该字母已被访问的标记
dfs(k+1); //继续放下一个字母
vis[i]=0; //返回时将字母访问标志去掉
}
}
int main(){
cin>>a;
n=strlen(a);
dfs(0);
return 0;
}