最長遞增子串行問題
它的英文專用名詞是
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 為,那麼最長遞增子串行為。以...