动态规划题目一:最长单调递增子序列

习题3-1:最长单调递增子序列

[算法设计与实验题解 page 63]

问题描述:
所谓子序列,就是在原序列里删掉若干个元素后剩下的序列,以字符串"abcdefg"为例子,去掉bde得到子序列"acfg"
现在的问题是,给你一个数字序列,你要求出它最长的单调递增子序列。

输入:
多组测试数据,每组测试数据第一行是n(1<=n<=10000),下一行是n个比1e9小的非负整数

输出:
对于每组测试数据输出一行,每行内容是最长的单调递增子序列的长度

样例输入:
5
1 2 4 8 16
5
1 10 4 9 7
9
0 0 0 1 1 1 5 5 5

样例输出:
5
3
3

我的Java 代码一:

/**
* 算法时间复杂度是O(n^2)
* 用数组b[0:n-1]记录以a[i],0<=i<n为结尾的元素的最长的递增子序列长度
* 序列a的最长的递增子序列的长度是max{b[i]}(0<=i<n),b[i]满足最优子结构,可以递归的定义:
* b[0]=1;b[i]=max{b[k]}+1 (0<=k<i,a[k]<a[i])
*/
import java.util.Scanner;

public class LIS {

public static int l;
public static int maxl;
public static int[] a;
public static int[] b;
public static void main(String[] args) {
Scanner sin
=new Scanner(System.in);
while(sin.hasNext()){
l
=sin.nextInt();
a
=new int[l];
b
=new int[l];//记住数组一定要初始化给定一个大小,不然后面赋值时会报空指针错误
for(int i=0;i<l;i++){
a[i]
=sin.nextInt();
}
maxl
=dp();
System.out.println(maxl);
}
}
private static int dp() {
int i,j,k,t;
t
=0;
b[
0]=1;
for(i=0;i<l;i++){
k
=0;
for(j=0;j<i;j++){
if(a[i]>a[j] && k<b[j]){
k
=b[j];
}
}
b[i]
=k+1;
}
for(i=0;i<l;i++){
if(t<b[i]){
t
=b[i];
}
}
return t;
}
}


我的Java 代码二:

/**
* 算法时间复杂度是O(nlog(n))
* 通过归纳假设得到问题变为:已知计算序列a的最长的递增子序列的长度k以及序列
* a中所有长度为k的递增子序列中的最小结尾元素b[k]
*/
import java.util.Scanner;

public class LIS2 {

public static int l;
public static int maxl;
public static int[] a;
public static int[] b;
public static void main(String[] args) {
Scanner sin
=new Scanner(System.in);
while(sin.hasNext()){
l
=sin.nextInt();
a
=new int[l];
b
=new int[l+1];
for(int i=0;i<l;i++){
a[i]
=sin.nextInt();
}
dp();
System.out.println(maxl);
}
}
private static void dp() {
int i,low,up,mid;
b[
1]=a[0];
maxl
=1;
for(i=1;i<l;i++){
if(a[i]>b[maxl]){//此时最大长度要加1,并且要改变最小元素值
maxl++;
b[maxl]
=a[i];
}
else if(a[i]<b[1]){//如果比第一个元素还要小,那么就换一下最小的元素值
b[1]=a[i];
}
else{//这种情况下要找到合适的位置将a[i]插入到b中的某个位置

low
=1;
up
=maxl;

// while(low!=up-1){//原书的写法
// mid=(low+up)/2;
// //System.out.println(low+" "+up+" "+mid);
// //System.out.println(b[mid]+" "+a[i]);
// if(b[mid]<=a[i]){//找到满足b[j-1]<=a[i]<b[j]的j(=up)
// low=mid;
// }else{
// up=mid;
// }
// //System.out.println(low+" "+up+" "+mid);
// }
// b[up]=a[i];

while(low<up){//另一种写法,更加符合二分查找
mid=(low+up)/2;//注意条件:low等于up时就要退出了
//System.out.println(low+" "+up+" "+mid);
//System.out.println(b[mid]+" "+a[i]);
if(b[mid]<=a[i]){//找到满足b[j-1]<=a[i]<b[j]的j(=up)
low=mid+1;
}
else{
up
=mid-1;
}
//System.out.println(low+" "+up+" "+mid);
}
b[up]
=a[i];
}
}
}
}

其他的资源:

可供参考的资料:

1.这道题目的两种解题算法总结博客:http://old.blog.edu.cn/user2/43845/archives/2006/1115309.shtml

2.国家集训队论文 李睿的论文:〈二分法和统计研究〉:http://wenku.baidu.com/view/313fbcd126fff705cc170a18.html

3.论坛中的其他解题方法:http://yzfy.org/dis/listpost.php?tid=101

转载于:https://www.cnblogs.com/yinger/archive/2011/07/20/2111269.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值