最长递增子序列(LIS)
最长递增子序列(Longest Increasing Subsequence) ,我们简记为 LIS。
题:求一个一维数组arr[i]中的最长递增子序列的长度,如在序列1,-1,2,-3,4,-5,6,-7中,最长递增子序列长度为4,序列为1,2,4,6。
解法一:快速排序+LCS
刚开始做这道题的时候,由于之前做过几道LCS的题,于是最先想到的是快速排序+LCS的方法。这种方法解决了当时只计算单个case的问题,但是后来面对计算多个 case的问题的时候,第一次遇到Memory Limit Exceeded。于是就意识到这种简单解法的时间和空间的复杂度都太高了。于是只能另寻他法。
public class Main {
static int n;
static int[] a;
static int[] b;
static int[][] z;
public static void QuickSort(int[] a){
QSort(a,1,n);
}
public static void QSort(int[] a,int p,int r){
if(p<r)
{
int q=Partition(a,p,r);
QSort(a,p,q-1);
QSort(a,q+1,r);
}
} public static int Partition(int[] a,int p,int r){
int x=a[r];
int i=p-1;
for(int j=p;j<r;j++)
{
if(a[j]<=x){
i=i+1;
swap(a, i, j);
}
}
swap(a, i+1, r);
return i+1;
}
public static void swap(int[] a, int i,int j){
int temp;
temp=a[j];
a[j]=a[i];
a[i]=temp;
}
public static int LCS(int a[],int[] b){
z=new int [n+1][n+1];
int i,j;
for( i=0;i<=n;i++)
z[i][0]=0;
for( j=0;j<=n;j++)
z[0][j]=0; for(i=1;i<=n;i++){
for( j=1;j<=n;j++){
if(a[i]==b[j]){
z[i][j]= z[i-1][j-1]+1;
}
else
z[i][j]=z[i-1][j] > z[i][j-1] ?z[i-1][j]:z[i][j-1];
}
}
return z[n][n];
}
public static void main(String[] args) {
int arr[] = {1,-1,2,-3,4,-5,6,-7};
n=arr.length;
a=new int[n+1];
b=new int[n+1];
int i,j;
for(i=1;i<=n;i++){
b[i]=a[i];
}
QuickSort(a);
//控制严格递增
for(i=1;i<n;i++){
for(j=i+1;j<=n;j++){
if(a[i]!=-1 && a[i]==a[j])
a[j]=-1;
}
}
System.out.println(LCS(a,b));
}
}
解法二:DP(O(N^2))
从后向前分析,很容易想到,第i个元素之前的最长递增子序列的长度要么是1(单独成一个序列),要么就是第i-1个元素之前的最长递增子序列加1,可以有状态方程:
LIS[i+1] = max{1,LIS[k]+1},aray[k],for any k <=i.
即如果array[i+1]大于array[k],那么第i+1个元素可以接在LIS[k]长的子序列后面构成一个更长的子序列。于此同时array[i+1]本身至少可以构成一个长度为1的子序列。
public int LIS(int[] arr, int size){int dp[40]; /* dp[i]记录到[0,i]数组的LIS */
for(int i = 0; i < size; ++i){int lis; /* LIS 长度 */
dp[i] = 1;
for(int j = 0; j < i; ++j){
if(arr[i] > arr[j] && dp[i] < dp[j] + 1){
dp[i] = dp[j] + 1;
if(dp[i] > lis){
lis = dp[i];
}
}
}
}
return lis;
}
解法三:二分查找+DP(O(nlogn))
在解法二中,当考察第i+1个元素的时候,我们是不考虑前面i个元素的分布情况的。现在我们从另一个角度分析,即当考察第i+1个元素的时候考虑前面i个元素的情况。
目的:我们期望在前i个元素中的所有长度为len的递增子序列中找到这样一个序列,它的最大元素比arr[i+1]小,而且长度要尽量的长,如此,我们只需记录len长度的递增子序列中最大元素的最小值就能使得将来的递增子序列尽量地长。
方法:维护一个数组MaxV[i],记录长度为i的递增子序列中最大元素的最小值,并对于数组中的每个元素考察其是哪个子序列的最大元素,二分更新MaxV数组,最终i的值便是最长递增子序列的长度。
仔细的分析请看最长递增子序列 O(NlogN)算法,
public class LIS {
/* 最长递增子序列 LIS
* 设数组长度不超过 30
* DP + BinarySearch
*/
static int[] MaxV=new int[30]; /* 存储长度i+1(len)的子序列最大元素的最小值 */
static int len; /* 存储子序列的最大长度 即MaxV当前的下标*/
static int BinSearch(int[] MaxV, int size, int x){ /* 返回MaxV[i]中刚刚不小于x的那个元素的下标 */
int left = 0, right = size-1;
while(left <= right){
int mid = (left + right) / 2;
if(MaxV[mid] <= x){
left = mid + 1;
}else{
right = mid - 1;
}
}
return left;
} static int getLIS(int[] arr, int size){
MaxV[0] = arr[0]; /* 初始化 */
len = 1;
for(int i = 1; i < size; ++i){ /* 寻找arr[i]属于哪个长度LIS的最大元素 */ if(arr[i] > MaxV[len-1]){ /* 大于最大的自然无需查找,否则二分查其位置 */ MaxV[len++] = arr[i];
}else{
int pos = BinSearch(MaxV,len,arr[i]);
MaxV[pos] = arr[i];
}
}
return len;
} /**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int arr[] = {1,-1,2,-3,4,-5,6,-7};
/* 计算LIS长度 */
System.out.println(getLIS(arr,arr.length));
}
}
参考资料:
《编程之美》 2.16
Felix’s Blog:最长递增子序列 O(NlogN)算法
勇幸|Thinking (http://www.ahathinking.com)
版权声明:本文为博主原创文章,未经博主允许不得转载。
最长递增子序列(LIS)的更多相关文章
- 2.16 最长递增子序列 LIS
[本文链接] http://www.cnblogs.com/hellogiser/p/dp-of-LIS.html [分析] 思路一:设序列为A,对序列进行排序后得到B,那么A的最长递增子序列LIS就 ...
- 动态规划(DP),最长递增子序列(LIS)
题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(d ...
- 最长回文子序列LCS,最长递增子序列LIS及相互联系
最长公共子序列LCS Lintcode 77. 最长公共子序列 LCS问题是求两个字符串的最长公共子序列 \[ dp[i][j] = \left\{\begin{matrix} & max(d ...
- 一个数组求其最长递增子序列(LIS)
一个数组求其最长递增子序列(LIS) 例如数组{3, 1, 4, 2, 3, 9, 4, 6}的LIS是{1, 2, 3, 4, 6},长度为5,假设数组长度为N,求数组的LIS的长度, 需要一个额外 ...
- 算法面试题 之 最长递增子序列 LIS
找出最长递增序列 O(NlogN)(不一定连续!) 参考 http://www.felix021.com/blog/read.php?1587%E5%8F%AF%E6%98%AF%E8%BF%9E%E ...
- 算法之动态规划(最长递增子序列——LIS)
最长递增子序列是动态规划中最经典的问题之一,我们从讨论这个问题开始,循序渐进的了解动态规划的相关知识要点. 在一个已知的序列 {a1, a 2,...an}中,取出若干数组成新的序列{ai1, ai ...
- 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现
关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已 ...
- 动态规划 - 最长递增子序列(LIS)
最长递增子序列是动态规划中经典的问题,详细如下: 在一个已知的序列{a1,a2,...,an}中,取出若干数组组成新的序列{ai1,ai2,...,aim},其中下标i1,i2,...,im保持递增, ...
- 最长递增子序列LIS再谈
DP模型: d(i) 以第 i 个元素结尾的最长递增子序列的长度. 那么就有 d(i) = max(d(j)) + 1;(j<i&&a[j]<a[i]),答案 max(d( ...
- POJ 1836 Alignment 最长递增子序列(LIS)的变形
大致题意:给出一队士兵的身高,一开始不是按身高排序的.要求最少的人出列,使原序列的士兵的身高先递增后递减. 求递增和递减不难想到递增子序列,要求最少的人出列,也就是原队列的人要最多. 1 2 3 4 ...
随机推荐
- OLTP和OLAP
1 OLTP和OLAP online transaction processing,联机事务处理.业务类系统主要供基层人员使用,进行一线业务操作,通常被称为联机事务处理. online analyti ...
- as2解析json
as2写的json解析,带容错,如果要做格式检查,得自己修改了,直接贴代码 //--------------------------------------------------json解析---- ...
- TextView属性
TextView及其子类,当字符内容太长显示不下时可以省略号代替未显示的字符:省略号可以在显示区域的起始,中间,结束位置,或者以跑马灯的方式显示文字(textview的状态为被选中). 其实现只需在x ...
- jQuery 中的 Deferred 和 Promises(转)
转自:http://www.css88.com/archives/4750/comment-page-1 看前首先了解:Promises/A规范,具体可以看这里,http://www.css88.co ...
- Django模型系统——ORM表结构对应关系
对于数据库来说一般表结构只会有三种对应关系,分别是一对一.一对多和多对一,下面分别介绍: 1.一对多 何为一对多,例如一个学生只可能有一个班级,一个班级却又多个学生,班级表和学生表就是一对多的关系. ...
- Docker的前世今生
核心知识点: 1.Docker的构想:对应用的封装.分发.部署.运行的生命周期的管理,一次封装到处运行 2.Docker的优点:一站式解决方案 3.Docker由LXC演变而来,迟迟没有集成到Linu ...
- iOS UIImage 拉伸问题 (适用于UIButton等需要局部拉伸的情况)
图片 有的切图切很大 还占用ipa大小,有时候 切图 只需要 局部或者说 一个压缩的图片的抽象状态 直接上代码 CGFloat top = ; // 顶端盖高度 ; // 底端盖高度 ; // 左端盖 ...
- Python lambda 匿名函数
lambda [arg1[, arg2, ... argN]]: expression Python使用lambda关键字创造匿名函数.所谓匿名,意即不再使用def语句这样标准的形式定义一个函数.这种 ...
- Linux服务器上的tomcat中部署web项目
首先了解一下下面几个概念,讲得不太准确:1.JVMJVM是class以及jar(实际上就是很多个class压缩在一起)的运行环境,特征就是java和javaw命令,通过这两个命令,你可以执行class ...
- 【leetcode刷题笔记】Unique Paths II
Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...