數組中最長的升序子序列(動態規劃問題)
阿新 • • 發佈:2017-11-22
ace dia mic enc namespace 進行 strong main log
The longest Increasing Subsequence (LIS)
給定一個序列,找到這個序列的一個最長的子序列,使得子序列的所有元素是升序的,且元素之間的相對位置不變(元素可以在原數組中不相鄰,但是相對位置不變)
比如, LIS for { 10, 22, 9, 33, 21, 50, 41, 60, 80 } 是 6,LIS 是 {10, 22, 33, 50, 60, 80}.
分析
arr[0…n-1]是輸入,然後L(i)是到元素i為止 LIS 的長度,也就是arr[i]作為 LIS 的最後一個元素時 LIS 的長度,那麽用遞歸形式 L(i) 可以寫作:
for(j<i)if(arr[j]<arr[i]) L(i) = {1+Max( L(j) )} if(j == 1) //遞歸的終止條件 L(i) = 1
所以這個問題可以將其分解為 subproblems 用遞歸進行解決:
#include <iostream> using namespace std; int LIS(int *arr, int n, int *max_ref) { if(n==1) return 1; int res, longest_here=1; for(int i = 1; i<n; ++i) { res = LIS(arr, i, max_ref);if(arr[i-1]<arr[n-1] && res+1>longest_here) longest_here = res+1; } if(*max_ref < longest_here) *max_ref = longest_here; return longest_here; } int main() { int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n = sizeof(arr)/sizeof(arr[0]); int max=1; LIS( arr, n,&max); cout<<max<<endl; return 0; }
非遞歸方法,這個需要開辟額外的存儲空間。
int LIS2(int *arr,int n) { int *longest_here = new int[n](); longest_here[0] = 1; int max = 1; for(int i = 1; i<n; ++i) { for(int j = 0; j<i; ++j) { if(arr[j]<arr[i] && longest_here[j]+1>longest_here[i]) longest_here[i] = longest_here[j]+1; } if(longest_here[i]>max) max = longest_here[i]; } delete []longest_here; return max; }
wiki上邊有時間復雜度為O(nlog(n))的解法
數組中最長的升序子序列(動態規劃問題)