一、遇到求下一个全排列的题目
这次通过看题解,了解到的是STL库中又一个强大的函数next_permutation()和prev_permutation(),它们所在的头文件为algorithm,其作用是求当前排列的下一个全排列和上一个全排列。
二、实现原理
这里就只说next_permutation()的原理,prev_permutation()的原理和next_permutation相反就行了。
当数组逆序是全排列的最后一个排列,找当前排列的下一个排列就是将原来序列变成逆序的下一步,直到当前序列全部为逆序时,寻找下一个排列将会失败。下面我们用整数类型来解释一下原理:
所以next_permutation的原理是从尾部开始两个相邻的元素数字a和数字b(a在前b在后),满足a < b然后在从尾端找到另一个数字c,满足a < c ,将a 和 c 对调,然后将b及其后面的元素颠倒排序即为求出的下一个序列。
next_permutation的原型如下:
template<class BidirectionalIterator>
bool next_permutation(
BidirectionalIterator _First,
BidirectionalIterator _Last
);
template<class BidirectionalIterator, class BinaryPredicate>
bool next_permutation(
BidirectionalIterator _First,
BidirectionalIterator _Last,
BinaryPredicate _Comp
);
cpp实现:
template<class BidirectionalIterator>
bool next_permutation(
BidirectionalIterator first,
BidirectionalIterator last
)
{
if(first == last)
return false; //空序列
BidirectionalIterator i = first;
++i;
if(i == last)
return false; //一个元素,没有下一个序列了
i = last;
--i;
for(;;) {
BidirectionalIterator ii = i;
--i;
if(*i < *ii) {
BidirectionalIterator j = lase;
while(!(*i < *--j));
iter_swap(i, j);
reverse(ii, last);
return true;
}
if(i == first) {
reverse(first, last); //全逆向,即为最小字典序列,如cba变为abc
return false;
}
}
}
prev_permutation就是从最尾端开始向前寻找两个相邻的元素,令第一个元素为i,第二个元素为ii,且满足i>ii。然后,从最尾端开始往前寻找第一个小于i的元素,令它为j。然后,将i和j对调,再将ii及其之后的所有元素反转。
三、使用next_permutation()
c语言的使用举栗
#include <stdio.h>
#include <algorithm>
using namespace std;
int main(){
int n;
while(scanf("%d",&n)&&n){
int a[1000];
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
do{
for(int i=0;i<n;i++)
printf("%d ",a[i]);
printf("\n");
}while(next_permutation(a,a+n));
}
return 0;
}
输入
3
1 2 3
输出
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1