ybt1199 全排列
ybt1199 全排列
【题目描述】
给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。
我们假设对于小写字母有‘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
【题解】
由于原数组使用字典序排列的,所以就不需要再次排序。
我们小学就学过全排列的基本思路:在确定首位的基础上,全排列其余位,然后依次更换首位,使所有元素在首位出现一遍,这样这一层递归就结束了。
这是一个典型的递归模型,在确定第x位的基础上,全排列x+1位及其后面的元素。所以递归函数就要分两部分:枚举第x位和全排列后面的位。
递归边界就是x=l(x是最后一位后面的一位)时,已经将第x位前面的元素(所有元素)的位置确定了下来,只要输出就好了。
实现这个算法,需要保证一个元素的位置确定后,不会出现第二次,这时,就要在确定a[i]成为b[x]的元素之前,走一遍b数组,查找是否有a[i]在b中出现过。若出现过,就找下一个符合条件的a[i]判断是否可以。
这样就可以写出递归函数:
void f(int x) {//x是当前数组b的长度,由于b是从0开始命名的,所以x也可以做本次操作的b的当前位的指针
if(x==l) {//递归边界,本次结束了,输出结果
for(int i=0; i<l; ++i)
cout<<b[i];
cout<<endl;
}
else {//没有结束,将b[x]的位置确定下来
bool bj=0;//判断a[i]是否在b中出现过将要使用的标记
char t;
for(int i=0; i<l; ++i) {//枚举第x位是a[i]
t=a[i];//提取a[i]并暂存
bj=0;
for(int j = 0; j < x; ++j) {//扫一遍b数组,判断a[i]是否在已排列的数组中出现
if(b[j]==t) {//已排列的数组中有a[i]
bj=1;//打标记
break;//跳出(已经找到了,再找下去也不会找到a[i]了,因为字符串不重复)
}
}
if(bj)//b[j]就是之前出现过的a[i],所以再找下一个a[i]放入b
continue;
else {
b[x] = a[i];//这是a[i]没有出现的情况,就把a[i]放到b[j+1]中。
f(x+1);//在确定前x位的基础上,全排列x+1位以及后面的元素
}
}
}
}
由于n个不重复元素的全排列有n!个,所以算法的复杂度可以达到nn,但是因为本题数据范围是1<=n<=6,所以这样暴力的复杂度完全没问题,接下来是完整代码:
#include<iostream>
#include<cstring>
using namespace std;
string a,b;
int l;
void f(int x)
int main() {
cin>>a;
l=a.length();
f(0);
return 0;
}
感谢题解的思路帮助。
除夕快乐!