[程序员代码面试指南]最长递增子序列(二分,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 ...
随机推荐
- java面试的一些问题
面向对象编程(OOP) Java是一个支持并发.基于类和面向对象的计算机编程语言.下面列出了面向对象软件开发的优点: 代码开发模块化,更易维护和修改. 代码复用. 增强代码的可靠性和灵活性. 增加代码 ...
- 利用Express+MySQL进行简单的增删改查
前言: 随着JavaScript语言的快速发展,其功能越来越强大,能做的事情也越来越多. 目前,web前端工程师能够利用NodeJS搭建服务,也成为了越来越多互联网公司对前端开发的硬性要求. 本文主要 ...
- 每日一道 LeetCode (19):合并两个有序数组
每天 3 分钟,走上算法的逆袭之路. 前文合集 每日一道 LeetCode 前文合集 代码仓库 GitHub: https://github.com/meteor1993/LeetCode Gitee ...
- Vue源码分析之数据驱动
响应式特点 数据响应式 修改数据时,视图自动更新,避免繁琐Dom操作,提高开发效率 双向绑定 数据改变,视图随之改变.视图改变,数据随之改变 数据驱动 开发时仅需要关注数据本身,不需要关心数据如何渲染 ...
- golang mysql demo
Go操作Mysql数据库 使用Go操作MySQL等数据库,一般有两种方式:一是使用database/sql接口,直接在代码里硬编码sql语句:二是使用gorm,即对象关系映射的方式在代码里抽象的操作数 ...
- FJOI2020 游记
Day -1 啥都不会,药丸 看了看统考题,好难,爆零的节奏 文化课OI双爆炸 尽力吧 Day 0 花三个多小时才到考场 福州真的好热 签到 在小礼堂待了一会,顺便给手机充了电 四点试机,今年用了新系 ...
- Navicat12 for Mysql激活
1 下载 注册机和Navicat网盘下载地址 链接:https://pan.baidu.com/s/1AFpQIlHCXVHc8OuBZ9PAlA 提取码:xvi2 2 安装 2 ...
- MyTerm入选北极代码库计划,喜获「Arctic Code Vault Contributor」勋章
- LeetCode 95 | 构造出所有二叉搜索树
今天是LeetCode专题第61篇文章,我们一起来看的是LeetCode95题,Unique Binary Search Trees II(不同的二叉搜索树II). 这道题的官方难度是Medium,点 ...
- .Net Task 异步执行不等待结果返回
该文章适合有一定异步编程基础的童鞋 开始之前先看.NET官网的一张图: 异步编程中最需弄清的是控制流是如何从方法移动到方法的. 没有理解的话可以去看一下 https://docs.microsoft. ...