最长上升子序列(贪心+二分)
Posted 4nc414g0n
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长上升子序列(贪心+二分)相关的知识,希望对你有一定的参考价值。
最长上升子序列(二)
题目链接
题目描述
:(贪心+二分,dp+二分
)
给定一个长度为 n 的数组a,求它的最长严格上升子序列的长度。
所谓子序列,指一个数组删掉一些数(也可以不删)之后,形成的新数组。例如 [1,5,3,7,3] 数组,其子序列有:[1,3,3]、[7] 等。但 [1,6]、[1,3,5] 则不是它的子序列。
我们定义一个序列是 严格上升 的,当且仅当该序列不存在两个下标 i 和 j 满足i<j 且 ai<=aj
输入:
[1,4,7,5,6]
输出:
4
思路
:
注意:dfs不能过
单dp也会超时
当a[i]比a[j]大时,相当于长度比dp[j]时的状态加一,为dp[j]+1,状态转移方程: dp[i]=max(dp[j]+1,dp[i]);for(int i=0;i<a.size();i++) for(int j=0;j<i;j++) if(a[i]>a[j]) dp[i]=max(dp[j]+1,dp[i]);
使用贪心加二分查找
贪心
:我们要使上升子序列尽可能的长,则我们需要让序列上升得尽可能慢,因此我们希望每次在上升子序列最后加上的那个数尽可能的小
另开辟一个升序数组tail,用来表示这个最长的升序子序列,变量end记录tail的尾部index
①
当index==0或者arr[index]>tail.back()的时候,直接将arr[index]加在tail最后面
②
当arr[index]<tail.back(),使用二分查找在tail数组里找到第一个大于arr[index]的元素,将arr[index]赋给它
返回end+1即为最长升序子序列个数代码如下:
int BSearch(int left, int right, vector<int>& tail,int num) while(left<right) int mid=(left+right)/2; if(tail[mid]>num) right=mid; else left=mid+1; return left; int LIS(vector<int>& a) if(a.empty()) return 0; vector<int> tail(a.size()); int end=-1; for(int i=0;i<a.size();i++) if(i==0||tail[end]<a[i]) end++; tail[end]=a[i]; else tail[BSearch(0,end,tail,a[i])]=a[i]; return end+1;
使用dp加二分查找
更简洁的写法参考:300. 最长递增子序列(动态规划 + 二分查找,清晰图解)
以上是关于最长上升子序列(贪心+二分)的主要内容,如果未能解决你的问题,请参考以下文章
贪心+二分查找:最长上升子序列(3.14 leetcode每日打卡)
AcWing 895 最长上升子序列 - (线性DP) or (贪心+二分优化)