[程序员代码面试指南]最长递增子序列(二分,DP)
2024-10-09 15:38:31
题目
例:arr=[2,1,5,3,6,4,8,9,7] ,最长递增子序列为1,3,4,8,9
题解
step1:找最长连续子序列长度
- dp[]存以arr[i]结尾的情况下,arr[0..i]中的最长递增子序列的长度。
- 额外加一个ends[]数组,初始化ends[0]=arr[0],其他为0。有一个有效区ends[0,r],只有有效区内的数才有意义。ends[i]=num表示遍历到目前,所有长度i+1的递增序列中,结尾最小的数时num。
- 遍历arr[i]时,在ends有效区找最左边>=arr[i]的数,从左到右找的过程表示能连在arr[i]前的连续序列的长度在不断增加。
- 若找到,记为ends[j],说明ends[j]及其后面的数都大于arr[I],故则dp[i]=j+1,ends[j]更新
- 若没找到,说明ends[]有效区的数都比arr[i]小,故dp[i]=有效区长度+1,有效区右边界r++,ends[r]更新。
- 因为ens[]是一个非递减序列,所以可以使用二分查找
- 时间复杂度O(nlogn)
step2:输出最长连续子序列元素
找到dp[]中存储的值=最长长度的元素,记为dp[i]对应的arr[i]即为最后一个元素。再往前找存储的值=最长长度-1&&对应的arr[j]<arr[i]的位置,即为倒数第二元素...
其他
- 这道题用到很经典的一种二分查找:找第一个比给定值大的元素的二分查找。
- 最终一定是l=r=mid,那么当最后一个元素大于所给元素,l指向它,l即所得。反之,++l,l也即所得。
- 所以:循环条件带=号,返回的是l,如果未找到将返回右边界+1的位置。
代码
public class Main {
public static void main(String args[]) {
int[] arr= {2,1,5,3,6,4,8,9,7};
int[] incSec=getLongestIncSeq(arr);
for(int num:incSec) {
System.out.println(num);
}
}
public static int[] getLongestIncSeq(int[] arr) {
if(arr==null||arr.length==0) {
return null;
}
int[] dp=getDp(arr);
return getIncSeq(dp,arr);
}
//得到dp数组
public static int[] getDp(int[] arr) {
int[] dp=new int[arr.length];
dp[0]=1;
int[] ends=new int[arr.length];
ends[0]=arr[0];
int end=0;
for(int i=0;i<arr.length;++i) {//遍历arr
int pos=firstBigger(arr[i],ends,end);//遍历ends
if(pos!=end+1) {//找到比arr[i]大的上升子序列结尾元素
//更新dp和ends
dp[i]=pos+1;//长度+1
ends[pos]=Math.min(ends[pos], arr[i]);
}
else {//未找到比arr[i]大的上升子序列结尾元素
//更新dp和ends
dp[i]=end+1+1;//原长度+1
++end;
ends[end]=arr[i];
}
}
return dp;
}
//二分查找第一个比num小的元素
public static int firstBigger(int num,int[] ends,int end) {//二分查找第一个比num小的元素
int l=0;
int r=end;
while(l<=r) {//**
int mid=(l+r)/2;//
if(ends[mid]>=num) {
r=mid-1;//
}
else {
l=mid+1;//
}
}
return l;//**
}
//输出最长递增子序列
public static int[] getIncSeq(int[] dp,int[] arr) {
int len=Integer.MIN_VALUE;//代表新数组长度 ,并表示新数组索引
int pos=-1;
for(int i=0;i<dp.length;++i) {
len=len>dp[i]?len:dp[i];
pos=len>dp[i]?pos:i;//dp索引,arr索引
}
int[] incSeq=new int[len];
incSeq[--len]=arr[pos];
for(int j=pos;j>=0;--j) {
if(dp[j]==len&&arr[j]<arr[pos]) {
incSeq[--len]=arr[j];
pos=j;
}
}
return incSeq;
}
}
最新文章
- How to install OpenBazaar Server in CentOS7
- 让Android程序获得系统的权限,实现关机重启,静默安装等功能
- 网页的Width ,Height
- C#编程总结(十三)数据压缩
- js获取url传递的参数
- win7下IIS配置MVC项目
- HTML浅学入门---基础知识 (1)<;基本规则>;
- Android中垃圾回收日志信息
- POJ_3273_Monthly_Expense_(二分,最小化最大值)
- IOS开发中 RunLoop,RunTime
- mysql下用户和密码生成管理
- 最详细最实用-Orcad10.5安装说明
- Oracle instant client在windows下的安装和使用
- 小记:Touchpad 禁用和启用
- __x__(25)0907第四天__ overflow 父元素对溢出内容的处理
- &#39;Settings&#39; object has no attribute &#39;FYFQ_URL_test&#39;
- 2019.03.23 Http
- 企业项目开发--本地缓存guava cache(2)
- 何凯文每日一句打卡||DAY6
- 1475 m进制转十进制
热门文章
- 【工具】OSS阿里云存储服务--超级简单--个人还是觉得Fastdfs好玩
- Maven工程 install和run包配置
- 你们要的MyCat实现MySQL分库分表来了
- 实现直方图均衡化(java+opencv)
- vue-cli的安装及版本查看/更新
- mysql join update
- Eligibility Traces and Plasticity on Behavioral Time Scales: Experimental Support of neoHebbian Three-Factor Learning Rules
- 多线程std::cout 深入研究
- C语言基础练习——打印菱形
- 安装openssl后yum不能使用的解决办法