目录
一、 题目
Description什么叫字典序,顾名思义就是按照字典的排列顺序。 以字典序为基础,我们可以得出任意两个数字串的大小。比如 "1" < "12"<"13"。 就是按每个数字位逐个比较的结果。 对于一个数字串的排列,可以知道最小的排列是从小到大的有序串“123456789”,而最大的排列串是从大到小的有序串 “987654321”。这样对于“123456789”的所有排列,将他们排序,即可以得到按照字典序排序的所有排列的有序集合。 因此,当我们知道当前的排列时,要获取下一个排列时,就可以找到有序集合中的下一个数(恰好比它大的)。比如, 当前的排列时“123456879”,那么恰好比它大的下一个排列就是“123456897”。 当目前的排列是最大的时候,说明 所有的排列都找完了。 输入格式请输入字串的长度n和字符串。(n<10) 注意: (1)字符串不含重复元素。 (2)这里初始输入的字串不一定是排列的有序集合中最小的那个,即使不是最小的那个,输出也一定要按照从小 到大的顺序输出。 输出格式字典序的每个排列,按序号输出。 输入样例3 214 输出样例1 124 2 142 3 214 4 241 5 412 6 421 提示这里两个办法来输出字典序的所有排列。 方法一: C++的STL真是个可以偷懒的好东西,用STL的next_permutation()函数,标准库全排列next_permutation()的返回值: bool类型。 假设数列:d1d2d3d4…… 范围由[first,last)标记,调用next_permutation使数列 逐次增大,这个递增过程按照字典序。 C++ Reference中next_permutation的函数声明如下: #include <algorithm> bool next_permutation( iterator start, iterator end ); The next_permutation() function attempts to transform the given range of elements [start,end) into the next lexicographically greater permutation of elements. If it succeeds, it returns true, otherwise, it returns false. 所以,将输入的数字序列用sort()或qsort()排下序,先找到最小的字典序排列,然后不断 调用next_permutation() 并输出,直至最后最大的一个。 方法二:思路同方法一,但自行编写计算一个当前字符串的下一个字典序排列。 设P是一个排列串:P = s[1]s[2]...s[n] = s[1]...s[j]...s[k]...s[n] 1)从当前排列串的右端开始,找出第一个比右边数字小的数字的序号j (j从左端开始计算),即 j=max{ i |s[i]<s[i+1]}; 2)在s[j]的右边的数字中,找出所有比s[j]大的数中最小的数字s[k], 即 k = max{ i |s[i]>s[j]} (对s[j]右边数来说,从右至左是递增的,因此k是所有大于s[j]的数字中序号最大者, 序号虽最大但s[k]是处于s[j]右边且比s[j]大的数中的最小者); 3)交换s[j]和s[k]; 4)再将s[j+1]...s[k-1]s[k]s[k+1]...s[n]倒转得到排列 P' = s[1]s[2]...s[j] s[n]...s[k+1]s[k]s[k-1]...s[j+1], 这里P'就是排列P的下一个排列。 简单来说,就是对于给定的一个数,首先从右边找到第一个相邻“有序对”(这个“有序对” 的定义是就是满足s[i]<s[i+1]最右边对)。 现假设下一个要找的数比这个数大,且中间没有一个数比前者大、比后者小。然后再重新从 右边起找出第一个比那个"有序对"的较小者要大的数,交换他们,再将那个较小数下标后面的 子数组反转。 总结一下:就是由后向前找替换数和替换点,然后由后向前找第一个比替换数大的数与替换数 交换,最后颠倒替换点后的所有数据。 例如,如何得到 346987521 的下一个字典序排列? 1)从尾部往前找第一个s(i-1) < s(i)的位置: ... 4 6 < 9 < 8 < 7 < 5 < 2 < 1 最终找到6是第一个变小的数字,记录下6的位置为i-1。 2)从i位置往后找到最后一个大于6的数。 ... 4 6 > 9 > 8 > 7 5 2 1 最终找到7的位置,记录位置为k。 3)交换位置i-1和k的值: 4 7 9 8 6 5 2 1 4)倒序i位置后的所有数据:4 7 1 2 5 6 8 9 则347125689为346987521的下一个排列。 |
二、 思路
采用方法一。
排序sort() + STL的next_permutation()
#include <algorithm> bool next_permutation( iterator start, iterator end ); The next_permutation() function attempts to transform the given range of elements [start,end) into the next lexicographically greater permutation of elements. If it succeeds, it returns true, otherwise, it returns false.
三、代码
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
int main()
{
int n;
scanf("%d\n",&n);
char ch[n];
for(int i=0; i<n; i++)
ch[i] = getchar();
for(int i=0; i<n; i++){
for(int j=0; j<n-i-1; j++){
if(ch[j]>ch[j+1]){
char c = ch[j];
ch[j] = ch[j+1];
ch[j+1] = c;
}
}
}
int p=1;
do{
printf("%d ",p++);
for(int i=0; i<n; i++){
cout<<ch[i];
}cout<<endl;
}while(next_permutation(ch,ch+n));
}
结果:
输入:
3
521
输出:
1 125
2 152
3 215
4 251
5 512
6 521
输入:
4
8532
输出:
1 2358
2 2385
3 2538
4 2583
5 2835
6 2853
7 3258
8 3285
9 3528
10 3582
11 3825
12 3852
13 5238
14 5283
15 5328
16 5382
17 5823
18 5832
19 8235
20 8253
21 8325
22 8352
23 8523
24 8532