您的位置:首页 > 其它

数组中最长的升序子序列(动态规划问题)

2017-11-22 12:15 218 查看
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
();
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))的解法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: