動態規劃-最長上升子序列(LIS)
阿新 • • 發佈:2018-11-04
時間複雜度為〇(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;
}