题目

例: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;
}
}

最新文章

  1. How to install OpenBazaar Server in CentOS7
  2. 让Android程序获得系统的权限,实现关机重启,静默安装等功能
  3. 网页的Width ,Height
  4. C#编程总结(十三)数据压缩
  5. js获取url传递的参数
  6. win7下IIS配置MVC项目
  7. HTML浅学入门---基础知识 (1)&lt;基本规则&gt;
  8. Android中垃圾回收日志信息
  9. POJ_3273_Monthly_Expense_(二分,最小化最大值)
  10. IOS开发中 RunLoop,RunTime
  11. mysql下用户和密码生成管理
  12. 最详细最实用-Orcad10.5安装说明
  13. Oracle instant client在windows下的安装和使用
  14. 小记:Touchpad 禁用和启用
  15. __x__(25)0907第四天__ overflow 父元素对溢出内容的处理
  16. &#39;Settings&#39; object has no attribute &#39;FYFQ_URL_test&#39;
  17. 2019.03.23 Http
  18. 企业项目开发--本地缓存guava cache(2)
  19. 何凯文每日一句打卡||DAY6
  20. 1475 m进制转十进制

热门文章

  1. 【工具】OSS阿里云存储服务--超级简单--个人还是觉得Fastdfs好玩
  2. Maven工程 install和run包配置
  3. 你们要的MyCat实现MySQL分库分表来了
  4. 实现直方图均衡化(java+opencv)
  5. vue-cli的安装及版本查看/更新
  6. mysql join update
  7. Eligibility Traces and Plasticity on Behavioral Time Scales: Experimental Support of neoHebbian Three-Factor Learning Rules
  8. 多线程std::cout 深入研究
  9. C语言基础练习——打印菱形
  10. 安装openssl后yum不能使用的解决办法