C 最長遞增子串(LIS)求解

2021-09-05 16:43:19 字數 2578 閱讀 3620

下文中提到的子串/子串行可能會有不同的理解,由於網上絕大部分人認為subsequence為子串行,substring為子串,所以以下內容都為子串行,如果本文發生歧義或者我有筆誤的話,請一律將以上兩個詞語視為subsequence

lis(longest increasing subsequence)最長遞增子串行問題是一道非常基礎的dp問題,這裡我們主要是為了給各位解釋解決dp問題的最重要的方法之一——記憶化搜尋,這裡僅講解複雜度為o(n2)的方法解決此問題,並且這裡我們只需要求出最長子序列長度,對具體是哪條子序列也不做討論,本文最後會附上o(nlogn)的解決問題的**,但不做過多的解釋說明。

在原來的串中刪掉一部分資料,並把剩下的資料按照原來的順序排列組成的乙個串稱為該串的子串行。

例如對於1、2、3、4、5、6、7、8、9這個串,1、2、3是它的子串行,1、3、9是它的子串行、1、2、3、4、5、6、7、8、9也是它的子串行(子串行可以為它本身),但是諸如1、4、3或1、3、3或1、9、2、3、4、5、6、7、8都不是該串的子串行。

這個很好理解,即此子串行按照順序遞增。在上面那個示例中,它的所有子串行都是遞增的(因為這個串本身就是遞增的串,所以它的所有子串行都是遞增的)。

這個就不用解釋了吧,上述例子中,它本身就是最長子序列

下面的討論過程中,我們採用

1、7、3、4、5、9、8、9

這串數列

這裡最長遞增子串行為1、3、4、5、8、9

1、我們假設這串數列只有第乙個資料(即只有1)

那麼我們可以確定,最長子序列長度為1。

2、這個時候我們加入第二個資料(即為1、7)

我們發現,7>1,也就是說,可以加入到這個答案之中,即最長子序列長度為2

3、這時候我們加入第三個資料——3,我們發現了乙個問題,如果要把3加入到最長串中,則必須拋棄掉7,組成1、3串。但無論是哪種情況(1、7還是1、3)都是長度為2的子串行。這個長度為2是怎麼判斷出來的?我們需要好好考慮一下,即如何用計算機語言解釋這個人腦的神奇思維過程。

我們可以這樣假設,1前面還有n個資料,1為第n+1個數、7是n+2、3是n+3.

這個時候,按照我們前面這樣做,3前面的資料已經組成很多的遞增串了,而如果3需要加入到前面這個「大家庭」中,則需要找到乙個串,其最末尾的資料小於3。

那我們如果要找到乙個對3而言最優的串(即最長的串)那麼就要在所有3可以加入的串中,找到最長的串。(如果沒有可以加入的串,長度即為1)

那麼我們可以把前面的每乙個資料/元素都寫成乙個串,即當我們考慮到此資料後,就把滿足此資料的最優的串儲存下來,然後讓下乙個資料去這些串內找最優的,並給這個新的資料附上乙個新的串。

例如,下乙個資料:4,在這之前我們有了以下這些串:1和1、7和1、3這樣三個串(第乙個串只有乙個資料1,因為對於1而言,前面沒有串,所以自行成串,而對於其他兩個資料,就沒有單獨的串了,原因:比如7,如果某個資料可以加入到7這個串末尾,則必定可以加入1、7這個串末尾),那麼很明顯,4可以加入到串為1或1、3,按照最優原則,則加入到1、3這個串中,組成1、3、4這個串,並儲存。以此類推,則可以得到如下**。示例1

7345

989此資料對應的最長串

11、7

1、31、3、4

1、3、4、5

1、3、4、5、9

1、3、4、5、8

1、3、4、5、8、9

這裡我們在比較時注意到乙個細節,乙個串唯一有意義的兩個資料分別是:最後乙個資料和當前長度。那麼也就是說,我們儲存的時候可以無視前面已經確定的串,只需要考慮最後一位的大小是否小於當前比較的引數。由於我們是把串儲存在當前數下的,所以這個串的最後乙個數等於這個數(上面的**中可以看出,下面的串的最後乙個值必定等於上面的資料)

那麼**可以簡化為如下:示例1

7345

989最長的串長度12

2345

56那麼我們只需要最後查詢一下最大的資料是多少即可。

這裡就直接給出**

#include

intmain()

for(i=

0; i}for

(i=0

; i)//這裡找出f中的最大值

printf

("%d\n"

,maxn)

;//輸出

return0;

}

最後,我給出另外一種可能理解較難的方法,思想仍是記憶化搜尋,但是複雜度只有o(nlogn),這裡就不對該**做過多解釋了。

#include

int maxn[

1005

],maxlen;

intfinddate

(int l,

int r,

int t)

int m=

(l+r)/2

;if(maxn[m]

>t)

else

}int

main()

maxn[0]

=a[0];

for(i=

1; i)else

}printf

("%d\n"

,maxlen)

;return0;

}

最長遞增子串行 LIS

對於這個問題,最直觀的dp方法是cnt i 表示以height i 結束的最長遞增子串行的元素的個數,遞迴方程是cnt i max for max i 0 i求出整個數列的最長遞增子串行的長度 if b i max max b i cout return 0 顯然,這種方法的時間複雜度仍為o n 2...

最長遞增子串行 LIS

給定乙個長度為n的陣列,找出乙個最長的單調自增子序列 不一定連續,但是順序不能亂 例如 給定乙個長度為6的陣列a,則其最長的單調遞增子串行為,長度為4.這個問題可以轉換為最長公共子串行問題。如例子中的陣列a,則我們排序該陣列得到陣列a 然後找出陣列a和a 的最長公共子串行即可。顯然這裡最長公共子串行...

最長遞增子串行(LIS)

300.longest increasing subsequence good 給定乙個長度為n的陣列,找出乙個最長的單調遞增子串行 不一定連續,當時先後順序不能亂 更正式的定義是 設l 是n個不同的實數的序列,l的遞增子串行是這樣乙個子串行lin 其中k1。比如陣列a 為,那麼最長遞增子串行為。以...