leetcode300 最长上升子序列(Medium)
题目来源:leetcode300 最长上升子序列
题目描述:
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n^2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
解题思路:
动态规划,时间复杂度O(n^2),见代码。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.empty()) return 0;
int ans=1;
vector<int> dp(nums.size(),0);//dp[i]表示以nums[i]结尾的前i个字符的最长子序列长度。
dp[0]=1;
for(int i=1;i<nums.size();i++){
int maxVal=0;
for(int j=0;j<i;j++){
//必须满足nums[j]<nums[i],才能以nums[i]结尾,在所有满足条件中找出最大的
if(nums[j]<nums[i]){
maxVal=max(dp[j],maxVal);
}
}
dp[i]=maxVal+1;//长度+1
ans=max(ans,dp[i]);//更新结果
}
return ans;
}
};
复杂度降低到 O(n log n) ,可以使用贪心+二分。(参考链接:讨论区链接)
参考代码:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.empty()) return 0;
int n=nums.size();
vector<int> dp(n+1,0);
int len=1;
dp[len]=nums[0];
for(int i=1;i<nums.size();i++){
if(nums[i]>dp[len]) dp[++len]=nums[i];
else{
int l=1,r=len,pos=0;// 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 pos 设为 0
while(l<=r){
int mid=l+(r-l)/2;
if(dp[mid]<nums[i]) {
pos=mid;
l=mid+1;
}
else r=mid-1;
}
dp[pos+1]=nums[i];
}
}
return len;
}
};