zoukankan      html  css  js  c++  java
  • 最长单调上升子序列(LIS) O(nlogn)求法

    常规的dp求LIS的时间复杂度为O(n2),对于n比较大的时候这是不能接受的。这时候我们就需要一个优秀的O(nlogn)的算法了。

    这个算法是基于贪心的思想,具体来说就是开一个序列数组b,记录已经求得的“最长上升子序列”,当扫到一个元素大于序列b的最后一个元素时,就直接将扫到的元素加入序列b,否则就在b数组中二分查找第一个大于扫到的元素的元素,将其替换,因为这样序列的“潜力值”更大。

    假设我们有一个序列{1,8,3,7,11,6,9,10}。
    初始化b数组的第0个元素小于序列中的最小元素(比如0或-1,上次就被这个坑了)。
      扫描到值1,1大于b中第0个元素,此时b为{1}
      扫描到这8,8大于b末尾元素,此时b为{1,8}
      扫描到3,3小于b末尾元素,二分查找替换掉8,此时b为{1,3}
      扫描到7,直接加入,此时b为{1,3,7}
      扫描到11,直接加入,此时b为{1,3,7,11}
      扫描到6,小于末尾元素,二分查找替换掉7,此时b为{1,3,6,11}(此时b并不是按照a中的顺序来了)
      扫描到9,小于末尾元素,二分查找替换掉11,此时b为{1,3,6,9}
      扫描到10,直接加入,此时b为{1,3,6,9,10}

    看完举的栗子,相信大家都多多少少明白,b中不一定记录的是a的单调上升序列,但是b数组的长度就是最长单调上升序列的长度了。

    这里以POJ Longest Ordered Subsequence给出代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstdio>
     4 using namespace std;
     5 
     6 int a[1001],b[1001];
     7 
     8 int n,len;
     9 int main(){
    10     b[0]=-1;
    11     scanf("%d",&n);
    12     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    13     for(int i=1;i<=n;++i){
    14         if(a[i]>b[len]){
    15             b[++len]=a[i];
    16         }else{
    17             int k=lower_bound(b+1,b+1+len,a[i])-b;
    18             b[k]=a[i];
    19         }
    20     }
    21     cout<<len;
    22     return 0;
    23 }
  • 相关阅读:
    -----------------------------2015年 年度总结-----------------------------
    ------第二节-----------------第二讲----单链表的基本操作---------
    shell 字符串截取
    express, mocha, supertest,istanbul
    Qunit 和 jsCoverage使用方法(js单元测试)
    jsp tutorial
    Unicode 和 UTF-8 是什么关系?
    wget -d --header
    python array
    responsive and functional programming RxJava
  • 原文地址:https://www.cnblogs.com/Asika3912333/p/11381769.html
Copyright © 2011-2022 走看看