最長遞增子串行 LIS

2021-08-19 21:15:46 字數 2015 閱讀 1643

最長遞增子串行問題

它的英文專用名詞是

lis: longest increasing subsequence.

問題描述

乙個數的序列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, 4, 8)等等。這些子串行中最長的長度是4,比如子串行(1, 3, 5, 8).

你的任務,就是對於給定的序列,求出最長上公升子串行的長度。

輸入

輸入的第一行是序列的長度n (1

<= n

<= 1000)。

第二行給出序列中的n個整數,這些整數的取值範圍都在0到10000。

輸出

最長上公升子串行的長度。
樣例輸入

7

1 7 3 5 9 4 8

樣例輸出

4
題目鏈結

解題思路

1. 找子問題

「求序列的前n個元素的最長上公升子串行的長度」是個子問題,但這樣分解子問題,不具有「無後效性」

假設f(n) = x,但可能有多個序列滿足f(n) = x。有的序列的最後乙個元素比 an+1小,則加上an+1就能形成更長上公升子串行;有的序列最後乙個元素不比an+1小……以後的事情受如何達到狀態n的影響,不符合「無後效性」

「求以ak(k=1, 2, 3…n)為終點的最長上公升子串行的長度」

乙個上公升子串行中最右邊的那個數,稱為該子串行的「終點」。

雖然這個子問題和原問題形式上並不完全一樣,

但是只要這n個子問題都解決了,那麼這n個子問題的解中,

最大的那個就是整個問題的解。

2.確定狀態:

子問題只和乙個變數--

數字的位置相關。

因此序列中數的位置k

就是「狀態」,

而狀態k

對應的「值」,

就是以ak做為「終點」的最長上公升子串行的長度。

狀態一共有n個。

3.找出狀態轉移方程:

maxlen (k)表示以ak做為「終點」的最長上公升子串行的長度

那麼:初始狀態:maxlen (1) =1

maxlen(k)=max

for(int i=1;i//求以第i個數為終點的最長上公升子串行的長度

for(int j=0;j//遍歷之前的數,察看以第j個數為終點的最長上公升子串行

if(a[i]>a[j])

dp[i]=max(dp[i],dp[j]+1);}}

cout

<<*max_element(dp,dp+n)0;}

時間複雜度為o(n^2)

!改進演算法

參考部落格

改進演算法的時間複雜度為nlonn

改進演算法思想如下:

其實就是模擬乙個棧

如果a[i]大於當前棧頂的元素

那麼a[i]入棧

else

當前棧是嚴格遞增的

在當前棧中二分查詢棧中的比它大的第1個數

然後替換掉那個數

這樣做,增大了最大遞增子串行增加元素的潛力

ac**

#include

#include

using

namespace

std;

const

int maxn=1005;

int a[maxn];

int main()

a[l]=temp;}}

cout

<}

最長遞增子串行 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 為,那麼最長遞增子串行為。以...