最長不下降子串行 LIS演算法

2021-10-04 05:54:16 字數 1196 閱讀 5258

給定乙個序列,求最長不下降子串行的長度

定義:a[1…n]為原始序列,dp[k]表示長度為k的不下降子串行末尾元素的最小值,len表示當前已知的最長子序列的長度

初始化:dp[1] = a[1]; len = 1;

現在我們已知最長的不下降子串行長度為1,末尾元素的最小值為a[1],那麼我們讓i從2到n迴圈,依次求出前i個元素的最長不下降子串行的長度,迴圈的時候我們只需要維護好dp這個陣列和len就可以了

重點是怎麼維護

我看了很多很多博主講的關於這個演算法,最後看到了這樣一篇部落格,感覺博主寫的超級棒,搞明白之後就有了這一篇部落格原版

新加進來乙個元素a[i]

如果這個元素大於等於dp[len],那就直接加到序列的末尾

dp[++len] = a[i] 即可

那如果這個元素a[i]小於dp[len]呢,那就說明之前的元素可能滿足不了len最大,那麼就需要找到乙個更有潛力,可以得到更優解的數把他替換掉

例如兩個數a[x] a[y] x < y 且a[x] < a[y] 且 dp[x] == dp[y]

這時候明顯選擇a[x]更有潛力,因為可能存在a[x] < a[z] < a[y]的情況,選擇a[x]可以得到更優的解

所以就是當陣列dp的值相同的時候,盡量選擇更小的a[x]

這個更有潛力的數就是在dp陣列中第乙個大於當前的a[i]的,第乙個意味著前面的都小於等於他

假設第乙個大於他的是dp[j],說明dp[1…j-1]都小於等於它,那麼它完全可以接上dp[j-1]然後生成乙個長度為j的不下降子串行,而且這個子串行比當前的dp[j]這個子串行更有潛力(因為這個數比dp[j]小)

所以就替換掉它就行了,也就是dp[j]=a[i]

尋找第乙個大於等於他的數

可以stl upper_bound 每次複雜度 logn

int a[

40005];

int dp[

40005];

intmain()

dp[1]

= a[1]

;//初始化

int len =1;

for(

int i=

2;i<=n;i++)}

printf

("%d\n"

,len)

;return0;

}

一道最長不下降子串行的板子題

最長不下降子串行LIS

最長上公升子串行問題是解決很多問題的根本,它能幫助你理解二分的思想。考慮一下 對於乙個序列 n nn 請你查詢n nn中最長的子串行a aa,使得任意 i i j 時 a i a i a i a i a i a i 例如乙個長度為5 55的n nn 5553 331112 22444 顯然,它的最長...

LIS最長不下降子串行

在乙個序列中找到乙個最長的子串行 可以不連續 使得這個子串行不下降,即非遞減的。核心部分找到狀態轉移方程 dp i max j 1,2,i 1 a j 附上我的 include include includeusing namespace std const int maxn 10010 int d...

最長不下降子串行 (LIS)

最長不下降子串行是這樣乙個問題 在乙個數字序列中,找到乙個最長的子串行 可以不連續 使得這個子串行是不下降 非遞減 的。令dp i 表示以a i 結尾的最長不下降子串行的長度,這樣對a i 來說就會有兩種情況。1 如果存在a i 之前的元素a j jdp i 2 它前面的元素均比它大,則dp i 1...