标签:
给定一个整数序列arr,长度为N,找到最长上升子序列(LIS),返回LIS的长度。
最长上升子序列的定义:
最长上升子序列问题是在一个无序的给定序列中找到一个尽可能长的由低到高排列的子序列,这种子序列不一定是连续的或者唯一的。
给出 [5,4,1,2,3],LIS 是 [1,2,3],返回 3
给出 [4,2,4,5,3,7],LIS 是 [4,4,5,7],返回 4
本题也是一个动态规划算法的典型应用。需要维护一个长度为N的数组dp;dp[i]代表在以arr[i]这个数 为结尾的情况下,arr[0...i]中的最长递增子序列长度。
方法一:复杂度O(n^2)求解数组dp
方法二:
在上个方法中,我们用线性复杂度求出arr[0...i-1]中作为倒数第二个数。此步骤可以利用二分的思想降低到O(logn);
/*
4.5 最长递增子序列
给定一个整数序列arr,长度为N,找到最长上升子序列(LIS),返回LIS的长度。
举例:
给出 [5,4,1,2,3],LIS 是 [1,2,3],返回 3
给出 [4,2,4,5,3,7],LIS 是 [4,4,5,7],返回 4
*/
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
//O(n^2)的复杂度
vector<int> getDp1(vector<int> &nums)
{
if (nums.empty())
{
return vector<int>();
}//if
int len = nums.size();
vector<int> dp(len, 0);
for (int i = 0; i < len; ++i)
{
dp[i] = 1;
for (int j = 0; j < i; ++j)
{
if (nums[i] >= nums[j])
{
dp[i] = max(dp[i], dp[j] + 1);
}//if
}//for
}//for
return dp;
}
//O(nlogn)的复杂度(针对不含重复元素的最长递增子序列)
vector<int> getDp2(vector<int> &nums)
{
if (nums.empty())
{
return vector<int>();
}//if
int len = nums.size();
vector<int> dp(len, 0), ends(len, 0);
dp[0] = 1;
ends[0] = nums[0];
int right = 0;
int l = 0, r = 0, m = 0;
for (int i = 1; i < len; ++i)
{
l = 0;
r = right;
/*采用二分的思想,降低复杂度*/
while (l <= r)
{
m = (l + r) / 2;
if (nums[i] < ends[m])
{
l = m + 1;
}//if
else {
r = m - 1;
}//else
}//while
right = max(right, l);
ends[l] = nums[i];
dp[i] = l + 1;
}//for
return dp;
}
//动态规划
int longestIncreasingSubsequence(vector<int> nums) {
// write your code here
if (nums.empty())
{
return 0;
}//if
vector<int> dp = getDp1(nums);
int maxLen = 0, len = dp.size();
for (int i = 0; i < len; ++i)
{
if (dp[i] > maxLen)
{
maxLen = dp[i];
}//if
}//for
return maxLen;
}
int main()
{
vector<int> v = { 5,4,1,2,3 };
cout << longestIncreasingSubsequence(v) << endl;
system("pause");
return 0;
}GitHub源码标签:
原文地址:http://blog.csdn.net/fly_yr/article/details/51366389