leetcode300. 最长递增子序列(动态编程贪婪分割)
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/
题目
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
用例
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
提示:
1 <= nums.length <= 2500
-104 <= nums[i] <= 104
进阶:
你可以设计时间复杂度为 O(n2) 的解决方案吗?
你能将算法的时间复杂度降低到 O(n log(n)) 吗?
思路
方法一
动态规划 记录第一个位置到每一个位置最大距离 O(n^2)
注意*max_element(dp.begin(),dp.end());取数组最大值
转移方程dp[i]=max(dp[j]+1,dp[i]) ,nums[i]>nums[j],i>j
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
vector<int>dp(n,1);
for(int i=0;i<n;++i){
for(int j=0;j<i;++j){
if(nums[j]<nums[i]){
dp[i]=max(dp[i],dp[j]+1);
}
}
}
return *max_element(dp.begin(),dp.end());
}
};
方法二
贪心
维护一个数组,记录在长度固定的情况下,结尾最小的那个元素的数值
对原序列进行遍历,将每位元素二分插入 cell 中。
如果 cell 中元素都比它小,将它插到最后
否则,用它覆盖掉比它大的元素中最小的那个。
思想就是让 cell 中存储比较小的元素。这样,cell 未必是真实的最长上升子序列,但长度是对的。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int len=1,n=nums.size();
vector<int>d(n+1,0);
d[len]=nums[0];
for(int i=1;i<n;++i){
if(nums[i]>d[len]){
d[++len]=nums[i];
}else{
int l=1,r=len,pos=0;//说明所有数都比nums[i]大,需要更新d数组
while(l<=r){
int mid=(l+r)>>1;
if(d[mid]<nums[i]){
pos =mid;
l=mid +1;
}else{
r=mid-1;
}
}
d[pos+1]=nums[i];
}
}
return len;
}
};
上一篇: Python 数字建模笔记 - 模拟退火算法(3)整数规划问题
下一篇: 整数规划