最长不降子序列的nlogn算法

最长不降子序列的nlogn算法 (转)

所谓“最长不降子序列问题”,就是在一个给定的序列中寻找一个子序列{ai}满足:

                       a1<=a2<=...<an

这个问题在一般教材上,往往会作为动态规划的引例。

即使用如下的状态转移方程进行计算:

                   F[i]=max{F[j]}+1     aj<=ai

但是它的复杂度是O(n^2)的,对于稍大的规模便无法承受。

那么有没有改进的方法呢?答案是肯定的。

----------------------------------------------------------------分割线------------------------------------------------------------------------------------------

我们维护一个数组C[i],这里C[i]表示F值为i的最小数。

不难发现   C[1]<=C[2]<=...<=C[n]

因此我们可以利用C[]通过二分查找确定F[j]的值。

----------------------------------------------------------------分割线------------------------------------------------------------------------------------------

实现如下:

const int N = 1001;

int a[N], C[N], f[N]; // f[i]用于记录a[0...i]的最大长度

int bsearch(const int *C, int size, const int &a)

{

    int l=0, r=size-1;

    while( l <= r )

    {

        int mid = (l+r)/2;

        if( a > C[mid-1] && a <= C[mid] ) return mid; // >&&<= 换为: >= && <

        else if( a < C[mid] ) r = mid-1;

        else l = mid+1;

    }

}

int LIS(const int *a, const int &n){

     int i, j, size = 1;

     C[0] = a[0]; f[0] = 1;

     for( i=1; i < n; ++i ){

          if( a[i] <= C[0] ) j = 0;                 // <= 换为: <

         else if( a[i] >C[size-1] ) j = size++;   // > 换为: >=

         else j = bsearch(C, size, a[i]);

         C[j] = a[i]; f[i] = j+1;

     }

     return size;

}

------------------------------------------------------------------分割线------------------------------------------------------------------------------------------

至此,我们了解了O(nlogn)的算法,它主要是利用了二分查找的方法对朴素的动态规划进行加速、优化,从而达到理想的效率。



转自:http://fqq11679.blog.hexun.com/21632261_d.html

你可能感兴趣的:(最长不降子序列的nlogn算法 )