首先要知道什麼是子串行?它和子串的區別:
子串是指字串中連續的n個字元。
子串行是指字串中不一定連續但先後順序不變的n個字元。
對於乙個給定的陣列,它的最長上公升子串行不一定唯一,但是最長上公升子串行的長度一定是確定的。
這裡我給出兩種方法分別是dpo(n2)的和貪心+二分的演算法。
(1)動態規劃dp。
我們可以想想之所以可以用動態規劃是因為動態規劃的乙個特點就是當前解可以由上乙個階段的解推出, 由此,把我們要求的問題簡化成乙個更小的子問題。子問題具有相同的求解方式,只不過是規模小了而已。最長上公升子串行就符合這一特性。我們要求n個數的最長上公升子串行,可以求前n-1個數的最長上公升子串行,再跟第n個數進行判斷。
所以我們可以設乙個狀態:f[i]表示以a[i]結尾的最長上公升子串行的長度。
狀態轉移方程:f[i]=max(f[i],f[j]+1) 1<=j#include
#include
#define maxn 1000
using
namespace std;
int n;
int a[maxn]
;int f[maxn]
;int
main()
ans=
max(ans,f[i]);
} cout }/*8389 207 155 300 299 170 158 65 */(2)貪心+二分 新建乙個ans陣列,用來記錄當前的「最長上公升子串行」,因為對於乙個上公升子串行,顯然其結尾元素越小,越有利於在後面接其他的元素,也就越可能變得更長。因此我們採用這樣的方法來維護ans陣列:對於每乙個a[ i ],如果a[ i ] > ans [當前最長的lis長度],就把 a [ i ]接到當前最長的lis後面,否則就需要用 a [ i ] 取更新 ans陣列。具體方法是,在ans陣列中找到第乙個大於等於a [ i ]的元素ans[ id ],用a [ i ]去更新 ans [id](這裡就是用到了貪心的思想)。至於找第乙個大於等於a [ i ]的元素ans[ id]我們就用到了二分,因為陣列ans是有序的(上公升的)。 板子**:#include
#include
#define maxn 100010
using
namespace std;
int n;
int a[maxn]
;int ans[maxn]
;int
fen(
int cnt,
int x)
return l;
}int
main()
} cout }最後提醒一下,結果ans陣列中的元素並不一定是最長上公升子串行,只是長度是最長上公升子串行的長度,因為它可能有後面的元素去替換前面的元素,但是子串行要求元素的順序是不能變的,所以它不一定是最長上公升子串行。 看個例題: 這一題用o(n2)的dp演算法只能過一半,所以可以用貪心+二分的方法。 ac**:#include
#include
#include
#include
using
namespace std;
int f[
100000
],h[
100000];
int a[
100000];
intmain()
len1=len2=1;
f[len1]
=a[1
];h[len2]
=a[1];
for(
int i=
2;i<=n;i++)}
for(
int i=
2;i<=n;i++)}
cout } 屬於簡單的經典的dp,求最長上公升子串行 lis 先研究了o n 2 的思路。令a i 表示輸入第i個元素,d i 表示從a 1 到a i 中以a i 結尾的最長子序列長度。對於任意的0 j i 1,如果a j a i 則a i 可以接在a j 後面形成乙個以a i 結尾的新的最長上公升子串行。對於... o nlogn 做法 貪心 二分 該想法是在o n 2 的動態規劃中進一步演化而來 p i 表示第i個元素,dp i 表示長度為i 1的lis結尾元素的最小值 利用貪心的思想,對於乙個上公升子串行,最後面的乙個元素越小,越有利於新增新的元素,這樣lis長度更長,所以我們要維護dp陣列,其表示的就是長... 題目 兩道題幾乎一樣,只不過對於輸入輸出的要求有所不同罷了。lis有兩種方法 一 第一種方法 時間複雜度為o n 2 狀態 dp i 區間為0 i的序列的lis 轉移方程 dp i max 1,dp k 1 0 k include include include include using name...最長上公升子串行 LIS 長度
最長上公升子串行的長度(LIS)
最長上公升子串行 LIS