关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已经做了实现,但是这种方法时间复杂度太高,查阅相关资料后我发现有人提出的算法可以将时间复杂度降低为O(nlogn),这种算法的核心思想就是替换(二分法替换),以下为我对这中算法的理解: 
假设随机生成的一个具有10个元素的数组arrayIn[1-10]如[2, 3, 3, 4, 7, 3, 1, 6, 6, 4],求这个数组的最长递增子序列。 
首先定义一个数组arrayOut[1-10]来逐个寻找arrayIn[1-10]中以第i个元素结尾的最长递增子序列的长度。 
定义len来计算相应的长度 
(1)将arrayIn[1]放入arrayOut,此时arrayOut[1]=arrayIn[1]=2,此时len=1; 
(2)将arrayIn[2]放入arrayOut,此时要先寻找arrayIn[2]应该放入的位置,由于arrayIn[2]=3>arrayOut[1]=2,那么arrayIn[2]应该放入的位置为arrayOut[2],这时arrayOut[2]=arrayIn[2]=3,此时len=2; 
(3)将arrayIn[3]放入arrayOut,此时要先寻找arrayIn[3]应该放入的位置,由于arrayIn[3]=3=arrayOut[2]=3,那么arrayIn[3]应该放入的位置为arrayOut[2],这时arrayOut[2]=arrayIn[3]=3,即此时进来的arrayIn[3]替换掉了arrayOut[2],此时len仍然为2; 
(4)对数组arrayIn的后续元素执行以上类似的操作即 
如果arrayIn要放入的元素比arrayOut最后一个元素大的话就放在其后; 
否则寻找一个替换的位置 
这样以来arrayIn元素放入的位置即为len的值,然后判断这次得到的len值与上次的len值的大小,向大的方向更新即可。 
使用二分法来查找arrayIn元素应该放入的位置即可将时间复杂度降为O(nlogn)。 
以下为具体的实现代码(java)

import java.util.Arrays;
import java.util.Random; public class LISUpdate { public static void main(String[] args){ System.out.println("Generating a random array...");
LISUpdate lisUpdate=new LISUpdate();
int[] oldArray=new int[10];
oldArray=lisUpdate.randomArray();
System.out.println(Arrays.toString(oldArray)); //输出生成的随机数组
System.out.println("each LIS array:"); //输出每次计算时arrayOut数组的内容,便于观察
System.out.println("LIS length nlogn is:"+lisUpdate.getLength(oldArray)); //输出最长递增子序列的长度
} public int[] randomArray(){ //生成一个10以内的数组,长度为10
Random random=new Random();
int[] randomArray=new int[10];
for (int i = 0; i < 10; i++) {
randomArray[i]=random.nextInt(10);
} return randomArray;
} public int BinarySearchPosition(int arrayOut[],int left,int right,int key){ //二分查找要替换的位置 int mid; if (arrayOut[right]<key) {
return right+1;
}else {
while(left<right){
mid=(left+right)/2;
if (arrayOut[mid]<key) {
left=mid+1;
}else {
right=mid;
}
}
return left;
} } public int getLength(int[] arrayIn){ //获取最长递增子序列的长度 int position;
int len=1; int[] arrayOut=new int[arrayIn.length+1];//arrayOut[0]没有存放数据
arrayOut[1]=arrayIn[0]; //初始化,长度为1的LIS末尾为arrayIn[0]
for (int i = 1; i < arrayIn.length; i++) {
position=BinarySearchPosition(arrayOut, 1, len, arrayIn[i]);
arrayOut[position]=arrayIn[i];
System.out.println(Arrays.toString(arrayOut));
if (len<position) {
len=position;
}
} return len;
}

需要注意的是:上面代码中输出的arrayOut数组并不是最长递增子序列,我这里选择将其输出只是为了验证算法的执行过程。

对于求最长递减子序列,则可以直接将原数组进行“反转”操作,然后求出反转之后的数组的最长递增子序列的长度即为最长递减子序列的长度。

最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现的更多相关文章

  1. 一个数组求其最长递增子序列(LIS)

    一个数组求其最长递增子序列(LIS) 例如数组{3, 1, 4, 2, 3, 9, 4, 6}的LIS是{1, 2, 3, 4, 6},长度为5,假设数组长度为N,求数组的LIS的长度, 需要一个额外 ...

  2. 2.16 最长递增子序列 LIS

    [本文链接] http://www.cnblogs.com/hellogiser/p/dp-of-LIS.html [分析] 思路一:设序列为A,对序列进行排序后得到B,那么A的最长递增子序列LIS就 ...

  3. 最长回文子序列LCS,最长递增子序列LIS及相互联系

    最长公共子序列LCS Lintcode 77. 最长公共子序列 LCS问题是求两个字符串的最长公共子序列 \[ dp[i][j] = \left\{\begin{matrix} & max(d ...

  4. 动态规划(DP),最长递增子序列(LIS)

    题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(d ...

  5. 最长递增子序列LIS再谈

    DP模型: d(i) 以第 i 个元素结尾的最长递增子序列的长度. 那么就有 d(i) = max(d(j)) + 1;(j<i&&a[j]<a[i]),答案 max(d( ...

  6. 算法面试题 之 最长递增子序列 LIS

    找出最长递增序列 O(NlogN)(不一定连续!) 参考 http://www.felix021.com/blog/read.php?1587%E5%8F%AF%E6%98%AF%E8%BF%9E%E ...

  7. 算法之动态规划(最长递增子序列——LIS)

    最长递增子序列是动态规划中最经典的问题之一,我们从讨论这个问题开始,循序渐进的了解动态规划的相关知识要点. 在一个已知的序列 {a1, a 2,...an}中,取出若干数组成新的序列{ai1, ai ...

  8. 动态规划 - 最长递增子序列(LIS)

    最长递增子序列是动态规划中经典的问题,详细如下: 在一个已知的序列{a1,a2,...,an}中,取出若干数组组成新的序列{ai1,ai2,...,aim},其中下标i1,i2,...,im保持递增, ...

  9. POJ 1836 Alignment 最长递增子序列(LIS)的变形

    大致题意:给出一队士兵的身高,一开始不是按身高排序的.要求最少的人出列,使原序列的士兵的身高先递增后递减. 求递增和递减不难想到递增子序列,要求最少的人出列,也就是原队列的人要最多. 1 2 3 4 ...

随机推荐

  1. nf_conntrack之解决方案

    1.现象 在/var/log/message中出现以下信息 Dec 8 11:22:29 product08 kernel: nf_conntrack: table full, dropping pa ...

  2. 摊铺机基本参数介绍(鼎盛天工WTD9501A)

    柴油水冷发动机,马力强劲,功率储备系数大,低噪音.低污染,经济性好,低温起动性能好.微电子控制,分别实现刮板输送.螺旋供料左右独立驱动,可实现自动供料,保持熨平板前物料均匀,调平系统响应速度快,调平精 ...

  3. Android编译系统环境过程初始化分析【转】

    本文转载自:http://blog.csdn.net/luoshengyang/article/details/18928789 Android源代码在编译之前,要先对编译环境进行初始化,其中最主要就 ...

  4. 使用shell自动备份数据库

    全备份 #!/bin/sh #mysql地址 #检测用户是否手动输入了密码 mysql_host="" #mysql用户 mysql_user="" #mysq ...

  5. C# 处理base64 以及base64的原理分析

    base64的原理, http://www.cnblogs.com/diligenceday/p/6002382.html http://www.cnblogs.com/chengxiaohui/ar ...

  6. winform获取文件路径

    1.取得控制台应用程序的根目录方法     方法1.Environment.CurrentDirectory 取得或设置当前工作目录的完整限定路径     方法2.AppDomain.CurrentD ...

  7. Qt之密码框不可全选、复制、粘贴无右键菜单等

    转载---> http://blog.sina.com.cn/s/blog_a6fb6cc90101artk.html 在做用户登录界面的时候,往往会用到密码框,则其中的一些功能也要求与普通的输 ...

  8. ZigzagConvert

    public class ZigzagConvert { public static String convert(String s, int nRows) { int len = s.length( ...

  9. Flume的Avro Sink和Avro Source研究之二 : Avro Sink

    啊,AvroSink要复杂好多:< 好吧,先确定主要问题: AvroSink为啥这么多代码?有必要吗?它都有哪些逻辑需要实现? 你看,avro-rpc-quickstart里是这么建client ...

  10. Nagios的基本安装配置

    //////////////////////nagios//////////////////////nagios原理:http://www.linuxidc.com/Linux/2013-11/927 ...