对于前面i个元素的任何一个递增子序列,如果这个子序列的最大的元素比array[i+1]小,那么就可以将array[i+1]加在这个子序列后面,构成一个新的递增子序列。
比如当i=4的时候,目标序列为:1,-1,2,-3,4,-5,6,-7最长递增序列为:(1, 2),(-1, 2)。那么,只要4>2,就可以把4直接增加到前面的子序列形成一个新的递增子序列。因此,我们希望找到前i个元素中的一个递增子序列,使得这个递增子序列的最大的元素比array[i+1]小,且长度尽量地长。这样将array[i+1]加在该递增子序列后,便可找到以array[i+1]为最大元素的最长递增子序列。
假设在数组的前i个元素中,以array[i]为最大元素的最长递增子序列的长度为lis[i]。
同时,假设:
长度为1的递增子序列最大元素的最小值为maxv[1];
长度为2的递增子序列最大元素的最小值为maxv[2];
......
长度为lis[i]的递增子序列最大元素的最小值为maxv[lis[i]]。
假如维护了这些值,那么,在算法中就可以利用相关的信息来减少判断的次数。
代码如下:
public int longestIncresingSubarray(int[] arr) {
if(null == arr || 0 == arr.length) {
return 0;
}
int len= arr.length;
int[] maxv = new int[len+1];
int[] lis = new int[len];
maxv[0] = Integer.MIN_VALUE;
maxv[1] = arr[0]; // 长度 1 的最长子序列中,最后一个数的最小值
// init
for(int i=0; i<len; ++i) {
lis[i] = 1;
}
int nMaxLis = 1; // 当前最长递增子序列长度
for(int i=1; i<len; ++i) {
int j = nMaxLis;
// 更新lis, j指向更新的maxv, 即长度为j的maxv
while(j >= 0) {
if(arr[i] > maxv[j]) {
lis[i] = j+1;
break;
}
--j;
}
//如果找到更长的最长递增子序列
if(lis[i] > nMaxLis) {
nMaxLis = lis[i];
maxv[lis[i]] = arr[i];
} else if(maxv[j] < arr[i] && maxv[j+1] > arr[i] ) {
maxv[j+1] = arr[i];
}
}
return nMaxLis;
}