题目

例: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)的更多相关文章

  1. [程序员代码面试指南]字符串问题-字符串匹配问题(DP)

    问题描述 字符串str,模式串exp. 必须保证str中无'.'和'星号'字符,并且exp中'星号'不出现在首位,且无连续两个'星号'.PS星号是字符只是暂时没找到markdown的星号转义字符. ' ...

  2. 程序员代码面试指南 IT名企算法与数据结构题目最优解

    原文链接 这是一本程序员面试宝典!书中对IT名企代码面试各类题目的最优解进行了总结,并提供了相关代码实现.针对当前程序员面试缺乏权威题目汇总这一痛点,本书选取将近200道真实出现过的经典代码面试题,帮 ...

  3. 程序员代码面试指南:IT名企算法与数据结构题目最优解

      第1章栈和队列 1设计一个有getMin功能的栈(士★☆☆☆) 1由两个栈组成的队列(尉★★☆☆) 5如何仅用递归函数和栈操作逆序一个栈(尉★★☆☆) 8猫狗队列(士★☆☆☆)10用一个栈实现另一 ...

  4. [程序员代码面试指南]递归和动态规划-最长公共子串问题(DP,LCST)

    问题描述 如题. 例:输入两个字符串 str1="1AB234",str2="1234EF" ,应输出最长公共子串"234". 解题思路 状 ...

  5. [程序员代码面试指南]递归和动态规划-最小编辑代价(DP)

    问题描述 输入 原字符串StrOrg,目标字符串StrTarget,插入.删除.替换的编辑代价ic,dc,rc.输出将原字符串编辑成目标字符串的最小代价. 解题思路 状态表示 dp[i][j]表示把s ...

  6. [程序员代码面试指南]第9章-在两个长度相等的排序数组中找到第k小的数(二分)

    题目 给定两个有序数组arr1和arr2,再给定一个整数k,返回所有的数中第k小的数. 题解 利用题目"在两个长度相等的排序数组中找到第上中位数"的函数 分类讨论 k < 1 ...

  7. [程序员代码面试指南]数组和矩阵问题-找到无序数组中最小的k个数(堆排序)

    题目链接 https://www.nowcoder.com/practice/6a296eb82cf844ca8539b57c23e6e9bf?tpId=13&tqId=11182&t ...

  8. 《程序员代码面试指南》第一章 栈和队列 最大值减去最小值小于或等于num的数量

    题目 给定整数数组arr和整数num,共返回多少的数组满足如下情况 max(arr[i...j]) - min(arr[i...j]) <= num max(arr[i...j])表示数组arr ...

  9. 《程序员代码面试指南》第一章 栈和队列 构造数组的MaxTree

    题目 给出一个无重复元素的数组,构造此数组的MaxTree, java代码 /** * @Description: 构造数组的MaxTree * @Author: lizhouwei * @Creat ...

随机推荐

  1. Linux学习笔记 一 第一章 Linux 系统简介

    Linux简介 一.UNIX与Linux发展史

  2. Mybatis-06-Lombok

    偷懒神器Lombok 1. 什么是Lombok? java library plugs build tools 2.使用步骤: 在IDEA中安装Lombok插件 在项目中导入lombok的jar包   ...

  3. 简述 jpg png gif png-8 png-24 的区别

    Gif  格式的特点: 1.透明性,GIF是一种布尔透明类型,既可以是全透明,又可以是不透明,但是不可以半透明: 2.动画    GIF支持动画. 3.无损耗性    GIF是一种无损耗的图像格式,也 ...

  4. 笔记:phpstudy、虚拟机CentOS安装、Linux命令

    一.phpstudy 1.phpstudy实现w(Windows)a(Apache)m(Mysql)p(php)环境 Apache  用来发布Web服务   80端口 MySQL   开源的建议灵活的 ...

  5. Dubbo直连方式

    目录 一.dubbo概述 1. 基本架构 2. dubbo 支持的协议 二.直连方法 三.创建服务提供者 1. 思路 1. 创建maven web 2. pom.xml 3. 创建实体 4. 创建服务 ...

  6. 使用Java8中的Optional类来消除代码中的null检查

    简介 Optional类是Java 8新增的一个类,Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException). —— 每个 Java 程序员都非常了解的异常 ...

  7. 区块链入门到实战(20)之以太坊(Ethereum) – 虚拟机(E.V.M.)

    作用:执行智能合约代码的引擎 以太坊(Ethereum)虚拟机是执行智能合约代码的引擎. 可以用某种语言,例如Solidity语言,开发智能合约程序,编译成以太坊(Ethereum)虚拟机支持的字节码 ...

  8. 如何通过seo技术提高网站对用户的友好度

    http://www.wocaoseo.com/thread-129-1-1.html    今天的天气又是29度,眼看着满大街的人都穿着短袖和衬衣了,自己也再不能穿个厚厚的外套出去了,要不会被别人笑 ...

  9. 用python导入20个G的json数据到Mysql数据库

    整体思路参考资料:https://blog.csdn.net/layman2016/article/details/79252499 作业:有一个16个G的跟疫情相关的json新闻大数据(articl ...

  10. Vue.js 实战教程(附demo)

    在实战之前,你需要对vuejs的基础语法有一定的了解,可以通过以下几个途径进行学习: vue.js官方文档:https://cn.vuejs.org/v2/guide/index.html vue.j ...