问题描述:
Given an unsorted array of integers, find the length of longest increasing subsequence.
Example:
Input:[10,9,2,5,3,7,101,18]
Output: 4 Explanation: The longest increasing subsequence is[2,3,7,101]
, therefore the length is4
.
Note:
- There may be more than one LIS combination, it is only necessary for you to return the length.
- Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
源码:
这题的tag是动态规划,我就不展示其他的做法,直接上动态规划。
首先看一下我自己的菜鸡思路,我用dp[i]表示以i为结尾的最长的递增序列长度(必须包含元素i)。那么递归方程可以写成如下格式:
dp[i] = max(dp[j]+1) ,其中j<i且nums[i]>nums[j]
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size(), result = 1;
if (n==0) return 0;
vector<int> dp(n, 1);
for (int i=1; i<n; i++){
int tmp = 1;
for (int j=0; j<i; j++){
if (nums[j]<nums[i]){
tmp = max(tmp, dp[j] + 1);
}
}
dp[i] = tmp;
result = max(result, tmp);
}
return result;
}
};
看了一下solution有个基于二分查找的方法,英文的我也没大看懂,还是翻了一下别人的博客。
dp[i]: 长度为i + 1的上升子列的结尾元素的最小值
遍历nums的每个元素,逐个与dp数组比较,更新dp数组中的元素或增长dp数组
更新的算法是:对于nums中的元素target,找到dp中大于等于target的最小元素,更新之;若target大于dp中最后一个元素,则将target置于dp后面一个位置,并增长dp
最终dp数组的长度就是nums的最大上升子列的长度
易证dp是一个单调递增数列,因此更新算法的查找过程可以用O(logn)的时间复杂度完成
时间95%,空间66%
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size(), result = 1;
if (n==0) return 0;
vector<int> dp;
dp.push_back(nums[0]);
for (int i=1; i<n; i++){
if (dp.back() < nums[i]){
dp.push_back(nums[i]);
}
else {
*lower_bound(dp.begin(), dp.end(), nums[i]) = nums[i];
}
}
return dp.size();
}
};
其中Low_bound就是找大于等于目标值的最小值的位置