最長上公升字串LCS 的n log n 演算法

2021-04-15 17:26:15 字數 1651 閱讀 2935

可以參考一下zoj-1986這題目。 

先回顧經典的o(n^2)的動態規劃演算法,設a[t]表示序列中的第t個數,f[t]表示從1到t這一段中以t結尾的最長上公升子串行的長度,初始時設f [t] = 0(t = 1, 2, ..., len(a))。則有動態規劃方程:f[t] = max (j = 1,  2, ..., t - 1, 且a[j] < a[t])。 

現在,我們仔細考慮計算f[t]時的情況。假設有兩個元素a[x]和a[y],滿足 

(1)x < y < t (2)a[x] < a[y] < a[t] (3)f[x] = f[y] 

此時,選擇f[x]和選擇f[y]都可以得到同樣的f[t]值,那麼,在最長上公升子串行的這個位置中,應該選擇a[x]還是應該選擇a[y]呢? 

很明顯,選擇a[x]比選擇a[y]要好。因為由於條件(2),在a[x+1] ... a[t-1]這一段中,如果存在a[z],a[x] < a[z] < a[y],則與選擇a[y]相比,將會得到更長的上公升子串行。 

再根據條件(3),我們會得到乙個啟示:根據f的值進行分類。對於f的每乙個取值k,我們只需要保留滿足f[t] = k的所有a[t]中的最小值。設d[k]記錄這個值,即d[k] = min (f[t] = k)。 

注意到d的兩個特點: 

(1) d[k]的值是在整個計算過程中是單調不上公升的。 

(2) d的值是有序的,即d[1] < d[2] < d[3] < ... < d[n]。 

利用d,我們可以得到另外一種計算最長上公升子串行長度的方法。設當前已經求出的最長上公升子串行長度為len。先判斷a[t]與d[len]。若a [t] > d[len],則將a[t]接在d[len]後將得到乙個更長的上公升子串行,len = len + 1, d[len] = a [t];否則,在d[1]..d[len]中,找到最大的j,滿足d[j] < a[t]。令k = j + 1,則有d[j] < a [t] <= d[k],將a[t]接在d[j]後將得到乙個更長的上公升子串行,同時更新d[k] = a[t]。最後,len即為所要求的最長上公升子串行的長度。 

在上述演算法中,若使用樸素的順序查詢在d[1]..d[len]查詢,由於共有o(n)個元素需要計算,每次計算時的複雜度是o(n),則整個演算法的時間複雜度為o(n^2),與原來的演算法相比沒有任何進步。但是由於d的特點(2),我們在d中查詢時,可以使用二分查詢高效地完成,則整個演算法的時間複雜度下降為o(nlogn),有了非常顯著的提高。需要注意的是,d在演算法結束後記錄的並不是乙個符合題意的最長上公升子串行! 

這個演算法還可以擴充套件到整個最長子序列系列問題,整個演算法的難點在於二分查詢的設計,需要非常小心注意。

solutiion for zoj 1986:

#include

" stdio.h

" unsigned 

intj,n,p,i,k1,k2,k3,len,a,d[

40002

];int

main(

void

) else

d[k2]

= a;}}

printf(

" %u/n

" ,len);

} return

0;}  

動態規劃 最長上公升字串問題

首先定義上公升字串,對於任意的0這道題首先想到利用動態規劃的思路,動態規劃的基本思想就是 問題的最優解如果可以由子問題的最優解推導得到,則可以先求解子問題的最優解,在構造原問題的最優解 若子問題有較多的重複出現,則可以自底向上從最終子問題向原問題逐步求解。因此這道題可以理解成兩個問題 在已知前n 1...

Dp 最長上公升子串 最長上公升子串行

乙個數的子串bi,當b1 b2 bs的時候,我們稱這個子串是上公升的。對於給定的乙個序列 a1,a2,an 我們可以得到一些上公升的子串 ai1,ai2,aik 這裡1 i1 i2 ik n。如 對於序列 1,7,3,5,9,4,8 有它的一些上公升子串,如 1,7 3,5,9 等等。這些子串中最長...

動態規劃 最長上公升字串 詞語接龍問題

def bfs arr,ajmatrix max length 0for i in range len arr 每乙個單詞都有可能被當作開頭 記錄遍歷過的單詞 history 以第i個單詞作為開頭 cur max 0 初始化以第i個單詞為開頭的最大長度 queue i,len arr i histo...