1. 程式人生 > >動態規劃-最長上升子序列(LIS)

動態規劃-最長上升子序列(LIS)

時間複雜度為〇(nlogn)的演算法,下面就來看看。

我們再舉一個例子:有以下序列A[]=3 1 2 6 4 5 10 7,求LIS長度。

我們定義一個B[i]來儲存可能的排序序列,len為LIS長度。我們依次把A[i]有序地放進B[i]裡。(為了方便,i的範圍就從1~n表示第i個數)

A[1]=3,把3放進B[1],此時B[1]=3,此時len=1,最小末尾是3

A[2]=1,因為1比3小,所以可以把B[1]中的3替換為1,此時B[1]=1,此時len=1,最小末尾是1

A[3]=2,2大於1,就把2放進B[2]=2,此時B[]={1,2},len=2

同理,A[4]=6,把6放進B[3]=6,B[]={1,2,6},len=3

A[5]=4,4在2和6之間,比6小,可以把B[3]替換為4,B[]={1,2,4},len=3

A[6]=5,B[4]=5,B[]={1,2,4,5},len=4 

A[7]=10,B[5]=10,B[]={1,2,4,5,10},len=5

A[8]=7,7在5和10之間,比10小,可以把B[5]替換為7,B[]={1,2,4,5,7},len=5

最終我們得出LIS長度為5。但是,但是!!這裡的1 2 4 5 7很明顯並不是正確的最長上升子序列。是的,B序列並不表示最長上升子序列,它只表示相應最長子序列長度的排好序的最小序列。這有什麼用呢?我們最後一步7替換10並沒有增加最長子序列的長度,而這一步的意義,在於記錄最小序列,代表了一種“最可能性”。假如後面還有兩個資料8和9,那麼B[6]將更新為8,B[7]將更新為9,len就變為7

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=200001;
int a[MAXN];
int d[MAXN];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    d[1]=a[1];
    int len=1;
    for(int i=2;i<=n;i++)
    {
        
if(a[i]>d[len]) d[++len]=a[i]; else { int j=lower_bound(d+1,d+len+1,a[i])-d; d[j]=a[i]; } } printf("%d\n",len); return 0; }