今天遇到个问题,让用java写生成全排列,结果用惯了next_permutaion(),gg……
这篇blog安排如下:
1. next_permutation 算法解析
2. 算法数学原理 why right?
我的系统里 STL里面的code是这样的
template
bool next_permutation(Iter first, Iter last)
{
if (first == last)
return false;
Iter i = first;
++i;
if (i == last)
return false;
i = last;
--i;
for(;;)
{
Iter ii = i;
--i;
if (*i < *ii)
{
Iter j = last;
while (!(*i < *--j))
{}
std::iter_swap(i, j);
std::reverse(ii, last);
return true;
}
if (i == first)
{
std::reverse(first, last);
return false;
}
}
}
设我们要变换的序列为 a[0,…,n−1] a [ 0 , … , n − 1 ]
以上就是这5个步骤了,下面举个例子说明这个问题。
设 a[0,…,n−1]=[1,2,3,4,5] a [ 0 , … , n − 1 ] = [ 1 , 2 , 3 , 4 , 5 ]
第二步会找到 i=3,ii=4 i = 3 , i i = 4
第3步会找到 j=4,a[j]>a[i] j = 4 , a [ j ] > a [ i ] ,
step 4,交换 a[j],a[i],a[]=[1,2,3,5,4] a [ j ] , a [ i ] , a [ ] = [ 1 , 2 , 3 , 5 , 4 ] ,因为 ii=4 i i = 4 , 所以reverse(ii,n),不变,得到 a[]=[1,2,3,5,4] a [ ] = [ 1 , 2 , 3 , 5 , 4 ]
why 这样做所得到的序列恰好为其后一个?
我们这样想,假设 s1<s2 s 1 < s 2 ,且 order(s2)=order(s1)+1 o r d e r ( s 2 ) = o r d e r ( s 1 ) + 1 则必然存在一个数 k,s.t.s1[k]<s2[k] k , s . t . s 1 [ k ] < s 2 [ k ] ,
有一下两个性质:
let, tail=(s1[k],…,s1[n−1]) t a i l = ( s 1 [ k ] , … , s 1 [ n − 1 ] ) , 即 s1 s 1 中第 k k 个元素及其后面的所有元素。这些元素和 s2 s 2 中末尾元素相同.
则 s2[k]=mintaili>s1[k]{taili} s 2 [ k ] = m i n t a i l i > s 1 [ k ] { t a i l i } , 否则可用一个更小的 tailj t a i l j 替换掉 s2[k] s 2 [ k ] .
(s1[k+1],…,s1[n−1]) ( s 1 [ k + 1 ] , … , s 1 [ n − 1 ] ) 一定单调不减,否则我们可以找到一个 i,s.t.i>k and s1[i]<s1[i+1] i , s . t . i > k a n d s 1 [ i ] < s 1 [ i + 1 ] , 对 (s1[i],…,s1[n−1]) ( s 1 [ i ] , … , s 1 [ n − 1 ] ) 做1一步操作得到更小的 s2 s 2
显然,next_permutation 生成的新序列瞒住这两个性质,或则得出这两个性质的过程就是next_permutaion 的过程.
next_permutaion 的时间复杂度为 O(n) O ( n ) , 所以生成整个全排列需要 O(n!n) O ( n ! n )