解決的問題:給定乙個序列,求最長不下降子串行的長度(nlogn的演算法沒法求出具體的序列是什麼)
定義:a[1..n]為原始序列,d[k]表示長度為k的不下降子串行末尾元素的最小值,len表示當前已知的最長子序列的長度。
初始化:d[1]=a[1]; len=1; (0個元素的時候特判一下)
現在我們已知最長的不下降子串行長度為1,末尾元素的最小值為a[1],那麼我們讓i從2到n迴圈,依次求出前i個元素的最長不下降子串行的長度,迴圈的時候我們只需要維護好d這個陣列還有len就可以了。
關鍵問題就是怎麼維護?
可以看出我們是要用logn的複雜度維護的。實際上利用了d陣列的乙個性質:單調性。(長度更長了,d[k]的值是不會減小的)
考慮新進來乙個元素a[i]:
如果這個元素大於等於d[len],直接讓d[len+1]=a[i],然後len++。這個很好理解,當前最長的長度變成了len+1,而且d陣列也新增了乙個元素。
如果這個元素小於d[len]呢?說明它不能接在最後乙個後面了。那我們就看一下它該接在誰後面。
準確的說,並不是接在誰後面。而是替換掉誰。因為它接在前面的誰後面都是沒有意義的,再接也超不過最長的len,所以是替換掉別人。那麼替換掉誰呢?就是替換掉那個最該被它替換的那個。也就是在d陣列中第乙個大於它的。第乙個意味著前面的都小於等於它。假設第乙個大於它的是d[j],說明d[1..j-1]都小於等於它,那麼它完全可以接上d[j-1]然後生成乙個長度為j的不下降子串行,而且這個子串行比當前的d[j]這個子串行更有潛力(因為這個數比d[j]小)。所以就替換掉它就行了,也就是d[j]=a[i]。其實這個位置也是它唯一能夠替換的位置(前面的替了不滿足d[k]最小值的定義,後面替換了不滿足不下降序列)
至於第乙個大於它的怎麼找……stl upper_bound。每次複雜度logn。
至此,我們就神奇的解決了這個問題。按照這個思路,如果需要求嚴格遞增的子串行怎麼辦?
仍然考慮新進來乙個元素a[i]:
如果這個元素大於d[len],直接讓d[len+1]=a[i],然後len++。這個很好理解,當前最長的長度變成了len+1,而且d陣列也新增了乙個元素。
如果這個元素小於等於d[len]呢?說明它不能接在最後乙個後面了。那我們就看一下它該接在誰後面。
同樣的道理,只是upper_bound的時候要特判一下。每次複雜度logn。
//最長不下降子串行nlogn song
#include#includeusing namespace std;
int a[40005];
int d[40005];
int main()
d[1]=a[1]; //初始化
int len=1;
for (int i=2;i<=n;i++)
}printf("%d\n",len);
return 0;
}
最長不下降子串行詳解(一)
由2019年位元組跳動第二次筆試開始學習,第一部分參考 最長不下降子串行nlogn以及輸出序列,作者milky way 對於普通的最長不下降子串行,每個數都要從頭開始遍歷,複雜度 為 利用序列的單調性。對於任意乙個單調序列,如 1 2 3 4 51 2 3 4 5 是單增的 若這時向序列尾部增添乙個...
最長不下降子串行
a1 t0 an a an 1 2 b an c d n 1 求該序列最長不下降子串行長度 n不是很大顯然可以暴力。n很大呢?那就不斷減迴圈節長度直至減到乙個閾值內,再暴力。正確性顯然,只要閾值不要設太小。include include include define fo i,a,b for i a...
最長不下降子串行
最長不下降子串行解法 第一種就是普通的dp方法 for int i 1 i n i dp 0 1 for int i 1 i n i ans max ans,dp i cout 主要記錄一下n logn的寫法 二分 主要思路 用乙個陣列 b 來記錄最長的子串行 一開始讓b 1 a 1 陣列a為輸入的...