题目大意:求最长递增子序列
解题思路:这道题,编程之美上有详细解答,
设lis[i]表示已第i个数字结尾的递增子序列的长度
lis[i+1] = max(1, lis[k] + 1) array[i+1] > array[k], k <= i
编程之美上方法一不介绍了,
这里介绍下方法二
增加一个数组mav[i]表示长度为i的最长递增子序列中的最大元素中的最小值
那么寻找那个满足条件的k时,不需要从 i 开始往后遍历找
#include <iostream>
#include <cstdio>
#include <cstring>
#include <climits>
using namespace std;
const int maxn = 1010;
int n;
int array[maxn], maxv[maxn], lis[maxn];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &array[i]);
lis[i] = 1;
}
lis[0] = -1;
maxv[1] = array[1];
maxv[0] = INT_MIN;
int maxlis = 1;
for(int i = 1; i <= n; i++)
{
int j;
for(j = maxlis; j >= 0; j--)
{
if(array[i] > maxv[j])
{
lis[i] = j + 1;
break;
}
}
if(lis[i] > maxlis)
{
maxlis = lis[i];
maxv[maxlis] = array[i];
}
else if(maxv[j] < array[i] && array[i] < maxv[j + 1])
{
maxv[j + 1] = array[i];
}
}
printf("%d\n", maxlis);
return 0;
}
方法3:
for(j = maxlis; j >= 0; j--)
{
if(array[i] > maxv[j])
{
lis[i] = j + 1;
break;
}
}
在求那个j时,改用二分搜索查询,可以把O(n^2)降为O(nlogn)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <climits>
using namespace std;
const int maxn = 1010;
int n;
int array[maxn], maxv[maxn], lis[maxn];
int binarysearch(int low, int high, int index);
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &array[i]);
lis[i] = 1;
}
lis[0] = -1;
maxv[1] = array[1];
maxv[0] = INT_MIN;
int maxlis = 1;
for(int i = 1; i <= n; i++)
{
int j = binarysearch(1, maxlis, i);
if(j != -1)
lis[i] = j + 1;
else
j = 0;
if(lis[i] > maxlis)
{
maxlis = lis[i];
maxv[maxlis] = array[i];
}
else if(maxv[j] < array[i] && array[i] < maxv[j + 1])
{
maxv[j + 1] = array[i];
}
}
printf("%d\n", maxlis);
return 0;
}
int binarysearch(int low, int high, int index)
{
int pre = -1;
while(low <= high)
{
int mid = (low + high) >> 1;
if(array[index] > maxv[mid])
{
pre = mid;
low = mid + 1;
}
else
high = mid - 1;
}
return pre;
}