zoukankan      html  css  js  c++  java
  • 最长上升子序列问题 nlogn 实现算法的简述

    首先举个例子说明最长上升子序列(longest increasing subsequence 缩写 LIS):

      1,4,6,2,3,7,5 中1,2,3,5 和1,4,6,7都是最长上升子序列,长度均为4,且相邻元素不能相等。

    LIS是动态规划中的经典问题,O(n2)的做法是设d(i)为以i为结尾的最长上升子序列的长度,状态转移方程为:d[i]=max{0,d[j]|j<i,A[j]<A[i]}+1。

    下面我们仔细思考以下情况:

      i<j时,d[i]=d[j],显然这种情况只能是A[i]>=A[j];这时我们计算 d[t](t>j且A[t]>A[i]),那么应优先选取以A[j]结尾的子序列作为A[t]的前缀序列,因为如果存在

    i<j<z<t,满足A[j]<A[z]<A[i]<A[t],子序列的长度会因z的存在而增加。

      由此我们使用数组D[k]保存满足d[t]=k的最小A[t],即D[k]=min{A[t]|d[t]=k};

      可以证明D[k]是严格单调递增的,即D[1]<D[2]<D[3]<……<D[len],

    证明如下:

      D[k]=min{A[t1]|d[t1]=k};

      D[k+1]=min{A[t2]|d[t2]=k+1};

      采用反证法,

      令A[t1]=D[k],A[t2]=D[k+1]

      假设A[t2]<A[t1];

      设以A[t2]结尾对应的子序列为S[1]~S[k],A[t2],  满足S[k]<A[t2].

      显然S[1]~S[k]是一个以S[k]为结尾的最长上升子序列,长度为k,

      则有A[t1]=D[k]<=S[k]<A[t2],与假设矛盾,故D为严格单调递增序列。

    于是利用D我们可以得到另外一种计算最长上升子序列的方法,并且可以边读边计算D,算法如下:

      1)设当前最大子序列长度为len,读入A[i];

      2)如果A[i]>D[len],则len++,D[len]=A[i];

      3)如果A[i]<=D[len],则从1~len中二分查找第一个k,使D[k]>=A[i],更新D[k]=A[i].

    代码如下:

     1   int n;//原序列长度
     2     cin>>n;
     3     memset(A, 0,sizeof A);
     4     memset(D, 0, sizeof D);
     5     int len=0;//当前最长子序列长度
     6     for(int i=0;i<n;i++){
     7         cin>>A[i];
     8         if(A[i]>D[len]){
     9             len++;
    10             D[len]=A[i];
    11         }
    12         else {
    13             int k=lower_bound(D, D+len, A[i])-D;//二分搜索D[k]>=A[i],更新D[k]
    14             D[k]=A[i];
    15         }
    16     }
    17     cout<<len<<endl;
    18     return 0;
  • 相关阅读:
    git如何进行远程分支切换
    js中实现多态
    css选择器中:first-child与:first-of-type的区别
    js实现图片延时加载的原理
    认识AMD、CMD、UMD、CommonJS
    CORS详解
    JS实现继承的五种方式
    jQuery.fn.extend() 函数详解
    Java基础面试题
    Java面试题集
  • 原文地址:https://www.cnblogs.com/Kiraa/p/5506540.html
Copyright © 2011-2022 走看看