定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则记录最小的那个最末元素。
注意d中元素是单调递增的,下面要用到这个性质。
首先len = 1,d[1] = a[1],然后对a[i]:若a[i]>d[len],那么len++,d[len] = a[i];
否则,我们要从d[1]到d[len-1]中找到一个j,满足d[j-1]<a[i]<d[j],则根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的)即 d[j] = a[i];
最终答案就是len
注意d中元素是单调递增的,下面要用到这个性质。
首先len = 1,d[1] = a[1],然后对a[i]:若a[i]>d[len],那么len++,d[len] = a[i];
否则,我们要从d[1]到d[len-1]中找到一个j,满足d[j-1]<a[i]<d[j],则根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的)即 d[j] = a[i];
最终答案就是len
利用d的单调性,在查找j的时候可以二分查找,从而时间复杂度为nlogn。
/* O(nlogn) solution */
/*
* 二分查找求大于等于x的下界
* 这里数组a是从下标1开始的
*/
int binary_search(int *a, int n, int x)
{
int left = 1;
int right = n;
while(left < right)
{
int mid = left + (right-left)/2;
if(a[mid] >= x) right = mid;
else left = mid+1;
}
return left;
}
unsigned int lis2(int a[], int n)
{
int *lis;
int len=0, max;
int i,j;
if( n == 0 ) return 0;
if( n == 1 ) return 1;
lis = (int *)malloc((n+1) * sizeof(int));
lis[++len] = a[0];
for(i = 1; i < n; i++)
{
if(a[i]>lis[len])
{
lis[++len] = a[i];
}
else {
j = binary_search(lis,len,a[i]);
lis[j] = a[i];
}
}
return len;
}