题目:
解答:
全排列的字典序生成算法:
1.字典序法
字典序法中,对于数字1、2、3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。例如对于5个数字的排列12354和12345,排列12345在前,排列12354在后。按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是54321。
字典序算法如下:
设P是1~n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn
1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即 j=max{i|pi<pi+1}
2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即 k=max{i|pi>pj}(右边的数从右至左是递增的,因此k是所有大于pj的数字中序号最大者)
3)对换pi,pk
4)再将pj+1......pk-1pkpk+1pn倒转得到排列p''=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个下一个排列。
例如839647521是数字1~9的一个排列。从它生成下一个排列的步骤如下:
自右至左找出排列中第一个比右边数字小的数字4 839647521
在该数字后的数字中找出比4大的数中最小的一个5 839647521
将5与4交换 839657421
将7421倒转 839651247
所以839647521的下一个排列是839651247。
关键几步:
从后向前找第一个小于后面数的值(a[i-1] < a[i])
从后向前找第一个大于a[i-1]的数位置j
交换a[i-1] a[j]
逆序i 到末尾所有
参考:http://leonard1853.iteye.com/blog/1450085
STL中的next_permutation源码:
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;
}
}
}
我的代码:
class Solution {
public:
void nextPermutation(vector<int> &num) {
if (num.size() <= 1)
return;
//ii 后一个元素 i 前一个元素
//j 从后向前数第一个大于i的元素
int i, ii, j;
i = num.size() - 1;
for (;;)
{
ii = i;
--i;
if (num[i] < num[ii])
{
j = num.size() - 1;
while (num[i] >= num[j])
--j;
swap(num[i], num[j]);
myReverse(ii, num.size()-1, num);
return;
}
if (i == 0)
{
myReverse(0, num.size() - 1, num);
return;
}
}
}
private:
void myReverse(int i, int j, vector<int> &num)
{
while (i < j)
{
swap(num[i], num[j]);
++i;
--j;
}
}
};