题目描述
Redraiment是走梅花桩的高手。Redraiment总是起点不限,从前到后,往高的桩子走,但走的步数最多,不知道为什么?
你能替Redraiment研究他最多走的步数吗?
样例输入
6
2 5 1 5 4 5
样例输出
3
提示
Example:
6个点的高度各为 2 5 1 5 4 5
如从第1格开始走,最多为3步, 2 4 5
从第2格开始走,最多只有1步,5
而从第3格开始走最多有3步,1 4 5
从第5格开始走最多有2步,4 5
所以这个结果是3。
输入描述
输入多行,先输入数组的个数,再输入相应个数的整数
输出描述
输出结果
输入例子
6
2
5
1
5
4
5
输出例子
3
算法实现
import java.util.Scanner;
/**
* Author: 王俊超
* Date: 2015-12-27 15:25
* Declaration: All Rights Reserved !!!
*/
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = scanner.nextInt();
}
System.out.println(lsiEnhance(a));
}
scanner.close();
}
/**
* 设f(i)表示L中以ai为末元素的最长递增子序列的长度。则有如下的递推方程:
* 这个递推方程的意思是,在求以ai为末元素的最长递增子序列时,找到所有序
* 号在L前面且小于ai的元素aj,即j<i且aj<ai。如果这样的元素存在,那么对
* 所有aj,都有一个以aj为末元素的最长递增子序列的长度f(j),把其中最大的
* f(j)选出来,那么f(i)就等于最大的f(j)加上1,即以ai为末元素的最长递增
* 子序列,等于以使f(j)最大的那个aj为末元素的递增子序列最末再加上ai;如
* 果这样的元素不存在,那么ai自身构成一个长度为1的以ai为末元素的递增子序列。
*
* @param a 待处理的数组
* @return 最长递增子序列长度
*/
private static int lisSimple(int[] a) {
int n = a.length;
int[] f = new int[n];
f[0] = 1;
for (int i = 1; i < n; i++) {
f[i] = 1;
for (int j = 0; j < i; j++) {
if (a[j] < a[i] && f[j] > f[i] - 1) {
f[i] = f[j] + 1;
}
}
}
return f[n - 1];
}
/**
* 在上一种算法中,在计算每一个f(i)时,都要找出最大的f(j)(j < i)来,由于f(j)没有顺序,
* 只能顺序查找满足aj < ai最大的f(j),如果能将让f(j)有序,就可以使用二分查找,这样算
* 法的时间复杂度就可能降到O(nlogn)。于是想到用一个数组B来存储“子序列的”最大递增子
* 序列的最末元素,即有B[f(j)] = aj在计算f(i)时,在数组B中用二分查找法找到满足
* j < i且B[f(j)] = aj < ai的最大的j,并将B[f[j]+1]置为ai。
*
* @param a
* @return
*/
private static int lsiEnhance(int[] a) {
int n = a.length;
float[] B = new float[n + 1];
B[0] = Integer.MIN_VALUE;
B[1] = a[0];
int len = 1;
int p, r, m;
for (int i = 1; i < n; i++) {
p = 0;
r = len;
while (p <= r) {
m = (p + r) / 2;
if (B[m] < a[i]) {
p = m + 1;
} else {
r = m - 1;
}
}
B[p] = a[i];
if (p > len) {
len++;
}
}
return len;
}
}