最長單調遞增子序列--幾種方法
阿新 • • 發佈:2019-02-20
設給定的序列為num[n]
1.O(n^2)的求法
動態規劃的方法
狀態定義:設dp[i] 表示以num[i]結尾的最長單調遞增子序列的長度
狀態方程:dp[i] = max(dp[k] + 1 | num[k] < num[i], 0<=k<i), dp[i]初值為1
求法如下:
2. O(nlogn)的求法void MaxSubsequence(int n) //求最長遞增子序列 { int ma=0; for(int i=0;i<n;i++) { dp[i]=1; for(int j=0;j<i;j++) if(num[j]<num[i] && dp[i]<dp[j]+1) dp[i]=dp[j]+1; if(ma<dp[i]) ma=dp[i]; } printf("%d\n",ma); }
空間換時間的方法 。
ind[i] :長度為i的單調遞增子序列的最後一個元素的值
具體方法為:將num序列的每一個元素插入到ind陣列中,插入位置通過二分查詢獲得,故複雜度為O(nlogn)。
ind的更新規則:插入資料比當前最後位置的資料大,直接將資料插入ind中;否則在ind中找到第一個比當前資料大 的位置(從左到右),替換當前位置的資料。 ind中的資料是有序的,所以可以用二分查詢。
注意:ind陣列中所儲存的元素不一定就是符合條件的子序列,但所求的長度卻是最大長度
eg:
num[]={2,3,5,1} 按照上述方法插入到ind陣列中,結果為:1,3,5。
最長單調遞增子序列長度為3,但1,3,5並不是符合要求的序列……
程式碼實現如下:
#include <iostream> #include <string> #include <algorithm> #include <string.h> const int INF = 0xffffff; const int NUM = 10; int ind[NUM]; int num[NUM]; int binary_search(int* array, int l, int r, int val) { int mid; while(l <= r) { mid = (l + r) / 2; if(val > array[mid]) l = mid + 1; else if(val < array[mid]) r = mid - 1; else return mid; } return l; } void LIS() { for(int i = 2; i < NUM; ++i) ind[i] = INF; ind[0] = -INF; ind[1] = num[0]; int ind_len = 2; int index; for(int i = 1; i < NUM; ++i) { index = binary_search(ind, 0, ind_len, num[i]); ind[index] = num[i]; if(index == ind_len) ind_len++; } std::cout << (ind[ind_len] == INF ? ind_len - 1 : ind_len) << std::endl; } int main() { for(int i = 0; i < NUM; ++i) std::cin >> num[i]; LIS(); return 0; }