1.lis含義:最長遞增子串行,可以連續,也可以不連續,只要是最長的就行,注意和連續遞增子串行的區別。
2.演算法功能:不僅可以求出給定序列的最長遞增子串行的長度,而且可以求出給定以序列中任意項結尾的最長遞增子串行的長度。
設數列a1,a2,a3,a4,a5........a(n-1),an, (也可以是字串);
a.解法:用動態規劃求解主要是動態方程的推導:
1.設dp[i] : 以a[i]結尾的最長遞增子串行的長度;
2.假設a[i]是a[j]的後繼,即a[i]>a[j] (j1,如果對於所有j:1-(i-1) a[i]<=a[j] 恆成立,那麼dp[i]=1
;3.由2可知:dp[i]=1
if(a[i]>a[j]) dp[i]=max (1
<=jfor(i=1;i
<=n;++i)
}
我們發現上述實現方法時間複雜度太高 對於較大資料不能採用這種方法
優化方案:用二分的思想來優化(必須有序)
步驟:1.設g[i]: 數列的遞增子串行長度為 i 時的最小結尾;
2.將a1放入g[1] 代表遞增子串行長度為1時的最小結尾是g[1];
3.將a[i] 插入到已經確定最小結尾的序列中 a[i] 的位置下標就代表以a[i]結尾的lis的長度;
4.直到將a(2-n)都插入到g陣列中演算法結束,g陣列的最大下標就表示a(1-n)的lis長度。
g陣列版:
g[1]=a[1];cnt=2;
for(i=2;i
<=n;++i)
vector版:
vector
vec; vector
::iterator iter;
vec.push_back(a[1]); //初始化將a[1]放進去
for(i=2;i<=n;++i)//迴圈插入剩餘元素
注意:1.在插入的過程之中我們發現g陣列是有序的所以採用了二分的方法;
2. lower_boune(begin,end,key) : 返回[begin,end) 位址區間內第乙個》=key的位址,用於嚴格單增;
upper_bound(begin , end , key) : 返回第乙個》key的位址, 用於非嚴格單增;
3.從以上過程中可以看到,我們不僅可以求出lis的長度,而且可以求出 以任意元素結尾的lis的長度 (如果需要用stl的容器儲存較方便);
4. 結論:給定串的 非嚴格 ,連續,單調減的子串個數等於該串的 最長,嚴格單調增的子串的長度(即lis長度); 證明:數列 a1,a2,a3,a4,a5,a6,a7; 假設此串的lis(唯一性)是a3,a5,那麼其他剩下的元素必然非嚴格,a1>=a2>a3 < a4 >=a5>=a6>=a7(可推廣到一般情況);
5.根據4可以推斷: 結論:給定串 非嚴格,單調增的子串個數等於該串的 最長,嚴格單減的最長字串的長度(lds長度);
6.如果題目中含有二維的要求,那麼將二維的轉化成一維的,然後就可以用lis的方法了(其實lis就是題目的盡頭,將題目中的條件適當轉化就變成特別簡單的問題了)。
列印lis:從頭開始逐個插入元素,每次插入只能插入到後面或者替換前一位插入的元素,這樣就可以列印lis了!!
#include
#include
#include
using
namespace
std;
vector
vec;
vector
::iterator iter;
int a[100];
void lis(int n)
}int main()
printf("\n");
}return
0; }
詳細講解: LIS問題分析
題目 原題這個lis問題,可不是longest increasing subsequence,而是largest independent set,含義如下 給定一棵二叉樹,找到滿足如下條件的最大節點集合 集合中的任意兩個節點之間,都沒有邊。如下圖 lis大小為5,為.分析 首先還是遞迴思想,比如對於...
動態規劃 LIS
最長遞增子串行 lis 的問題是要找到乙個給定序列的最長子序列的長度,使得子串行中的所有元素被排序的順序增加。例如,lis的長度是6和 lis為。最優子結構 對於長度為n的陣列a n 假設假設我們想求以aj結尾的最大遞增子串行長度,設為l j 那麼l j max l i 1,where i j a ...
動態規劃 LIS
動態規劃是比較重要的演算法啦,打算慢慢寫幾篇部落格總結一下。動態規劃的基本思想是 要求原問題的解,先求出更小一些的問題的解,由子問題的解通過某種方式得到原問題的解。以上是有關動態規劃的一些基本概念和概括。第一篇就先講一下最長遞增子串行 lis 的問題的解決。給出乙個數列a,求a的乙個 長度最大的子數...