生成全排列----std::next_permutation 算法解析

今天遇到个问题,让用java写生成全排列,结果用惯了next_permutaion(),gg……

这篇blog安排如下:
1. next_permutation 算法解析
2. 算法数学原理 why right?

next_permutation

我的系统里 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,,n1] a [ 0 , … , n − 1 ]

  1. 判断序列是否合法 , e.g.: [0] 只有一个数不合法
  2. 若合法,从后往前扫描序列,确定是否存在一个 i,s.t.a[i]<a[ii],(i[0,n1),ii=i+1) i , s . t . a [ i ] < a [ i i ] , ( i ∈ [ 0 , n − 1 ) , i i = i + 1 )
  3. 若不存在,过程结束,返回false,否则进入4
  4. for jn1 j ← n − 1 to 0 ,找到第一个 j,s.t.a[j]>a[i] j , s . t . a [ j ] > a [ i ] , (remark: 一定存在否则第三步就结束了)
  5. 交换 a[i],与a[j],reverse([ii,n)),return true

以上就是这5个步骤了,下面举个例子说明这个问题。

a[0,,n1]=[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 ] ,

有一下两个性质:

  1. let, tail=(s1[k],,s1[n1]) 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 ] .

  2. (s1[k+1],,s1[n1]) ( 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[n1]) ( 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 )

你可能感兴趣的:(算法刷题)