问题描述:给定一个数组a[a1,a2,a2......an],求它的最长递增的子数组长度。子数组是指该数组里的元素在位置的前后关系上保持原数组的关系。
最朴素的思想:求出以数组中每一个位置结尾的的最长递增子序列,选择其中的最大值,时间复杂度为O(n*n)。
现在有一种更巧妙的思想可以将时间复杂度变为O(n*logn),一看到logn我们很容易想到二分,使用二分的前提条件是有序,那么如何能够达到有序呢?
最长递增子序列O(n*logn)解法:首先开一个辅助数组h,长度和a数组相同,从a数组的第一个位置开始遍历,当前位置下标为i,在辅助数组h中去找第一个大于a[i]的数,用a[i]替换;如果h中没有大于a[i]的数,则将a[i]依次放在h数组中,这样我们保证了h数组中的数是有序的,可以使用二分查找,遍历一遍,h数组中保存的数的个数就是数组a的最长递增子序列长度。
private static int arrUp(int[] a) {
int[] h = new int[a.length];
h[0] = a[0];// 初始h[0]的值为a[0]
int length = 0;// 记录h数组中当前的下标
int l = 0;
int r = length;
for (int i = 0; i < a.length; i++) {
l = 0;
r = length;
while (l <= r) {
int mid = (l + r) / 2;
if (h[mid] < a[i]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
length = Math.max(l, length);// 更新标记位置
h[l] = a[i];// 将找到的位置替换为a[i]
}
// 数组从0开始,下标+1为其长度
return length + 1;
}