最长递增子串问题,用DP加上二分的思路,时间复杂度可以缩减到n*logn,原来的二维DP算法时间复杂度是n*n的
#include <stdio.h>
int min_tail[2000]; //min_tail[len]表示当前长度为len的递增子串的最小的尾数
int src[2000];
//在min_tail[1:len]中寻找min_tail[i]小于target的最大的i
int bin_search(int target, int len){
int l, r, m;
l = 1; r = len;
while(1){
if(r < l)
break;
m = (l+r)/2;
if(min_tail[m] < target){
if(m+1<=len && min_tail[m+1]<target){
l = m+1;
continue;
}
return m;
}
else
r = m-1;
}
return 0;
}
void func(int n){
int max_len, i;
int last_len;
if(0 == n){
printf("%d\n", 0);
return;
}
max_len = 1;
min_tail[max_len] = src[1];
for(i=2; i<=n; i++){
last_len = bin_search(src[i], max_len);
//src[i]作为末尾可以组成长度是last_len+1的递增子串
if(last_len == max_len){
//进入这个分支说明src[i]作为末尾可以得到当前最长的递增子串
max_len++;
min_tail[max_len] = src[i];
}
else{
//进入这个分支说明src[i]作为末尾的最长递增子串的长度已经出现过了,需要更新min_tail[last_len+1]
if(min_tail[last_len+1] > src[i])
min_tail[last_len+1] = src[i];
}
}
printf("%d\n", max_len);
}
int main(void){
int i, n;
//freopen("input.dat", "r", stdin);
while(scanf("%d", &n) != EOF){
for(i=1; i<=n; i++)
scanf("%d", src+i);
func(n);
}
return 0;
}