最长递增子序列(LIS) 贪心+二分详解O(nlogn)
Posted C_YCBX Py_YYDS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长递增子序列(LIS) 贪心+二分详解O(nlogn)相关的知识,希望对你有一定的参考价值。
从递增的三元序列引进贪心
题目
O(N)贪心解法
这种O(n)的方法妙处在于:我们不需要关心这三个数字的相对位置,只管更新长度为1、2的递增序列的结尾的最小数字,一旦遇上比长度为2的最小结尾数字要大的,则必出现递增的三元递增序列。
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
//用于更新长度为1的递增序列的最小尾数,以及长度为2的递增序列的最小尾数
int first = INT_MAX;
int second = INT_MAX;
for (int t : nums) {
//更新第一小的数字
if (t <= first) {
first = t;
} else if (t <= second) {
//更新第二小的数字(因为只有比第一小的数字大才能走到这一步)
second = t;
} else {
//一旦前面两步都没执行,比前面两个都大的数字出现了
return true;
}
}
return false;
}
};
最长递增子序列(LIS)的贪心+二分解法
题目
贪心+二分详解
首先我们如果要实现二分过程,那么就必须保证过程中所保存的数据是要有序的,而如果用
LCS
的方法进行变种,则不可能保证有序,所以我们另想办法进行有序处理,我们如上一种题目一样,把dp[i]
记录长度为i+1
递增序列的结尾最小元素,比如1,2,1,3
中长度为2的最小结尾元素对应:dp[1] = 2,对应序列:1,2
.
- 对应的动画更新过程:
这样便保证了每次查找的对象是有序的,便可以用二分进行查找优化了。
- 效率差距如此之大!
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int>dp(nums.size(),0);
int end = 1;
dp[0] = nums[0];
//寻找上边界的二分,我选择的是左闭右开的方式,注意如果存在相同元素,则直接不能算作一个长度
for(int i=1;i<nums.size();i++){
int l=0,r=end;
int target=nums[i];
while(l<r){
int mid = (l+r)/2;
if(dp[mid]>target)
r = mid;
else if(dp[mid]<target)
l = mid+1;
else{
l = mid;
break;
}
}
dp[l] = target;
//注意更新右边界
if(l==end)
end++;
}
return end;
}
};
以上是关于最长递增子序列(LIS) 贪心+二分详解O(nlogn)的主要内容,如果未能解决你的问题,请参考以下文章
最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现
[Mdp] lc673. 最长递增子序列的个数(LIS+算法优化+算法拓展)