[程序员代码面试指南]最长递增子序列(二分,DP)
题目
例: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;
}
}
[程序员代码面试指南]最长递增子序列(二分,DP)的更多相关文章
- [程序员代码面试指南]字符串问题-字符串匹配问题(DP)
问题描述 字符串str,模式串exp. 必须保证str中无'.'和'星号'字符,并且exp中'星号'不出现在首位,且无连续两个'星号'.PS星号是字符只是暂时没找到markdown的星号转义字符. ' ...
- 程序员代码面试指南 IT名企算法与数据结构题目最优解
原文链接 这是一本程序员面试宝典!书中对IT名企代码面试各类题目的最优解进行了总结,并提供了相关代码实现.针对当前程序员面试缺乏权威题目汇总这一痛点,本书选取将近200道真实出现过的经典代码面试题,帮 ...
- 程序员代码面试指南:IT名企算法与数据结构题目最优解
第1章栈和队列 1设计一个有getMin功能的栈(士★☆☆☆) 1由两个栈组成的队列(尉★★☆☆) 5如何仅用递归函数和栈操作逆序一个栈(尉★★☆☆) 8猫狗队列(士★☆☆☆)10用一个栈实现另一 ...
- [程序员代码面试指南]递归和动态规划-最长公共子串问题(DP,LCST)
问题描述 如题. 例:输入两个字符串 str1="1AB234",str2="1234EF" ,应输出最长公共子串"234". 解题思路 状 ...
- [程序员代码面试指南]递归和动态规划-最小编辑代价(DP)
问题描述 输入 原字符串StrOrg,目标字符串StrTarget,插入.删除.替换的编辑代价ic,dc,rc.输出将原字符串编辑成目标字符串的最小代价. 解题思路 状态表示 dp[i][j]表示把s ...
- [程序员代码面试指南]第9章-在两个长度相等的排序数组中找到第k小的数(二分)
题目 给定两个有序数组arr1和arr2,再给定一个整数k,返回所有的数中第k小的数. 题解 利用题目"在两个长度相等的排序数组中找到第上中位数"的函数 分类讨论 k < 1 ...
- [程序员代码面试指南]数组和矩阵问题-找到无序数组中最小的k个数(堆排序)
题目链接 https://www.nowcoder.com/practice/6a296eb82cf844ca8539b57c23e6e9bf?tpId=13&tqId=11182&t ...
- 《程序员代码面试指南》第一章 栈和队列 最大值减去最小值小于或等于num的数量
题目 给定整数数组arr和整数num,共返回多少的数组满足如下情况 max(arr[i...j]) - min(arr[i...j]) <= num max(arr[i...j])表示数组arr ...
- 《程序员代码面试指南》第一章 栈和队列 构造数组的MaxTree
题目 给出一个无重复元素的数组,构造此数组的MaxTree, java代码 /** * @Description: 构造数组的MaxTree * @Author: lizhouwei * @Creat ...
随机推荐
- 获取网页js代码的一个方法
这个是看了别人的代码,稍加修改而成的.怕时间长忘了,在这里记一笔: console.log(require(["foo:bar.js"]).prototype.someMethod ...
- Vue学习(十三)模版引擎算是预处理器吗?
前言 今天在看vue-loader预处理器配置相关的内容,突然看到了Pug,然后有了一个疑问:模版引擎原来是预处理器吗? 答案是:YES 说明 这里重点讨论使用不同的js模板引擎作为预处理器, 下面示 ...
- Linux C++实现一服务器与多客户端之间的通信
通过网络查找资料得到的都是一些零碎不成体系的知识点,无法融会贯通.而且需要筛选有用的信息,这需要花费大量的时间.所以把写代码过程中用到的相关知识的博客链接附在用到的位置,方便回顾. 1.程序流程 服务 ...
- SpringCloud简记_part2
Zookeeper服务注册与发现 1)Eureka停止更新了,你怎么办? https://github.com/Netflix/eureka/wiki 2)SpringCloud整合Zookeeper ...
- vue-cli的安装及版本查看/更新
vue-cli的安装及版本查看更新 vue-cli安装 npm install vue-cli -g vue-cli的版本查看 vue -V vue-cli的3.0+以后使用的不是vue-cli了,如 ...
- SpringBoot--- Shiro(拦截,认证)、Thymeleaf(模板引擎)
SpringBoot--- Shiro(拦截,认证).Thymeleaf(模板引擎) 环境 IDEA :2020.1 SpringBoot: 2.3.3 Java : 8 版本依赖: shiro- ...
- GitHub 热点速览 Vol.34:亚马逊、微软开源项目带你学硬核技术
作者:HelloGitHub-小鱼干 摘要:站在巨人的肩膀上才能看得更远,本周上榜的 computervision-recipes 便是典型代表,这个由微软开源的计算机视觉最佳实践项目,多次上 Git ...
- Windows 下mysqldump备份1045错误解决办法
一.我写的备份脚本如下 set d=%date:~0,4%%date:~5,2%%date:~8,2% C:\mysqldump -uroot -ptest@2018 --all-databases ...
- 3种 Springboot 全局时间格式化方式,别再写重复代码了
本文收录在个人博客:www.chengxy-nds.top,技术资料共享,同进步 时间格式化在项目中使用频率是非常高的,当我们的 API 接口返回结果,需要对其中某一个 date 字段属性进行特殊的格 ...
- Pyinstaller打包: 将资源文件或文件夹打包到最后生成的exe中
前提:用pyinstaller打包时部分资源文件可以利用qrc转成py文件来读取,但是有部分文件类型不适用. 原理:Pyinstaller 将资源文件一起打包到exe中.当exe运行时,会生成一个临时 ...