摘要:带重复数字的排列
思想:
比如S[]=1 2 3 4 9 7 6 5
先从右往左,找第一个比右边的数小的数.显然找到i=3(下标从0开始)
注意,这里找到这个数后,隐含的含义就是从i+1到结尾,按降序排列。
找到这个数后,再从右往左找,第一个比S[i]大的数,找到5.
之所以要这么找,无非是要把这个数变大(字典序的定义),而之所以找第一个,是因为S(这里指12349765这个序列)的下一个字典序是S集合能形成的所有序列中大于S的第一个,因此我们只想它增大一小点。而刚好,从右开始找的话,因为从右往左是升序(如前所说,隐含i+1到结尾为降序),因此找到的第一个比S[i]大的数,就是符合要求的数。到这里,交换数字4和5.
交换以后,i+1到结尾仍然是降序,因为我们交换了一个比刚才未交换时还小的数过去。
所以,这个时候把i+1到结尾反转,即reverse(i+1,end)
那么,反转过后,i+1到end这个串,就是i+1到end这些元素能组合成的最小的值,满足我们找字典序的要求。
#include <iostream>
#include <algorithm>
using namespace std;
const int size = 200;
char array[size+1] = {0};
int n = 0;
void reverse(int i)
{
int end = n - 1;
int begin = i;
for(; end>begin; begin++, end--){
swap(array[begin], array[end]);
}
}
bool findNext()
{
int i=n-1;
int j=n-1;
for(i=n-2; i>0; i--){
if(array[i] < array[i+1]){
break;
}
}
for(; j>i; j--){
if(array[j] > array[i]){
break;
}
}
if(j <= i){
return false;
}
swap(array[i], array[j]);
reverse(i+1);
return true;
}
int main()
{
char ch;
n = 0;
while(cin >> ch){
array[n++] = ch;
}
array[n] = '/0';
sort(array, array+n);
cout << array << endl;
while( findNext() ){
cout << array << endl;
}
return 0;
}