[程序员代码面试指南]最长递增子序列(二分,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 ...
随机推荐
- Linux学习笔记 一 第一章 Linux 系统简介
Linux简介 一.UNIX与Linux发展史
- Mybatis-06-Lombok
偷懒神器Lombok 1. 什么是Lombok? java library plugs build tools 2.使用步骤: 在IDEA中安装Lombok插件 在项目中导入lombok的jar包 ...
- 简述 jpg png gif png-8 png-24 的区别
Gif 格式的特点: 1.透明性,GIF是一种布尔透明类型,既可以是全透明,又可以是不透明,但是不可以半透明: 2.动画 GIF支持动画. 3.无损耗性 GIF是一种无损耗的图像格式,也 ...
- 笔记:phpstudy、虚拟机CentOS安装、Linux命令
一.phpstudy 1.phpstudy实现w(Windows)a(Apache)m(Mysql)p(php)环境 Apache 用来发布Web服务 80端口 MySQL 开源的建议灵活的 ...
- Dubbo直连方式
目录 一.dubbo概述 1. 基本架构 2. dubbo 支持的协议 二.直连方法 三.创建服务提供者 1. 思路 1. 创建maven web 2. pom.xml 3. 创建实体 4. 创建服务 ...
- 使用Java8中的Optional类来消除代码中的null检查
简介 Optional类是Java 8新增的一个类,Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException). —— 每个 Java 程序员都非常了解的异常 ...
- 区块链入门到实战(20)之以太坊(Ethereum) – 虚拟机(E.V.M.)
作用:执行智能合约代码的引擎 以太坊(Ethereum)虚拟机是执行智能合约代码的引擎. 可以用某种语言,例如Solidity语言,开发智能合约程序,编译成以太坊(Ethereum)虚拟机支持的字节码 ...
- 如何通过seo技术提高网站对用户的友好度
http://www.wocaoseo.com/thread-129-1-1.html 今天的天气又是29度,眼看着满大街的人都穿着短袖和衬衣了,自己也再不能穿个厚厚的外套出去了,要不会被别人笑 ...
- 用python导入20个G的json数据到Mysql数据库
整体思路参考资料:https://blog.csdn.net/layman2016/article/details/79252499 作业:有一个16个G的跟疫情相关的json新闻大数据(articl ...
- Vue.js 实战教程(附demo)
在实战之前,你需要对vuejs的基础语法有一定的了解,可以通过以下几个途径进行学习: vue.js官方文档:https://cn.vuejs.org/v2/guide/index.html vue.j ...