题面
给定一个全由小写字母构成的字符串,求它的全排列,按照字典序从小到大输出。
输入格式:
一行,一个字符串,长度不大于8。
输出格式:
输出所有全排列,每行一种排列形式,字典序从小到大。
输入样例:
在这里给出一组输入。例如:
abc
输出样例:
在这里给出相应的输出。例如:
abc
acb
bac
bca
cab
cba
题解
基本想法是找到先将所有的字母按照字典序排序完成 同时建立一个order数组来保存顺序,最初的顺序就是从0到8。然后只要通过对于order数组的变换不断输出就可以得到答案。
通过观察不难发现 对比上一个 下一个就是从末尾开始找,找到第一个仍旧是按照字典序排列的位置 即order[i]<order[i+1]的位置 用end来表示这个位置i 意味着这个位置必定被下一个替换
然后再通过从end到n进行处理 通过一个函数range(int l, int r)。l和r来标识范围 由于仍旧按照字典序排列 所以要找到最小的比order[l]大的那个数字 为了通用性以及能够思路比较清晰所以还是用了循环来解决 其实找order[i]+1好像也可以?(没有实践有待商榷欢迎指正)
然后将这两个数直接进行交换 这样就能够保证l位置 即 end位置的数字的正确 对于end后面的数字再进行排序(比较懒所以直接暴力了 排序可以优化)
这样完成之后下一步又会是最后两个交换 然后最后三个交换以此类推
Talk is cheap show me the code:
#include<stdio.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int order[9];
char str[9];
void range(int l, int r)
{
int nexti=l+1;
for(int i=l+1;i<=r;i++)
{
if(order[i]>order[l]&&order[i]<order[nexti])
{
nexti=i;
}
}//找到要和l交换的位置
int temp;
temp=order[l];
order[l]=order[nexti];
order[nexti]=temp;
//完成order[l]位置
for(int i=l+1;i<=r;i++)
for(int j=i;j<=r;j++)
{
if(order[i]>order[j])
{
int tem;
tem=order[i];
order[i]=order[j];
order[j]=tem;
}
}
//对于后面的进行排序
}
void Initorder()
{
for(int i=0;i<9;i++)
order[i]=i;
}
void Order(int n){
int end=n;
while(order[end]<order[end-1]){
end--;
}//从末尾开始找第一个递增的 用end来保存
end--;
if(end<1)
return;
range(end,n);//将end 开始到n的重新开始0排列
}
void output(int n)
{
for(int i=1;i<=n;i++)
printf("%c",str[order[i]]);
Order(n);
}
int main(){
int n;
scanf("%s",str+1);
n=strlen(str+1);
Initorder();
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
if(str[i]>str[j])
{
int tem;
tem=str[i];
str[i]=str[j];
str[j]=tem;
}
}
//按照字典序排列
int time=1;
for(int i=1;i<=n;i++)
time*=i;
while(time)
{
output(n);
if(time-1)
printf("\n");
time--;
}
system("pause");
}
平时做题没有写注释的习惯 回头看起来真的累 所以就在blog里整理一下了 希望能够有对别人也有所帮助 我只是一个新手 如果有更好的优化也欢迎交流