我们从样例的角度来考虑这个问题
上面为样例,下面为最长上升子序列的长度
我们设 len 表示上升子序列的长度,我们考虑 len = 1 的情况
当上升子序列的长度为 1 时,结尾的数的选择有两个:1 和 3 ,这时我们考虑,选哪个更好
注意到 a[2] = 2 ,因此如果我们选择 3 的话,那么 f[2] 只能为 1 ,但如果我们选择 1 的话, f[2] 就可以为 2
也就是说,当上升子序列的长度固定时,结尾的数越小越好,这样我们便有更大的可能性得到一个更长的上升子序列
我们用 q[i] 表示当上升子序列长度为 i 时所对应的数为 q[i] ,我们设定初始的最长上升子序列长度 len 为 0
每当我们变遍历到一个新数 a[i] 时,我们动态调整 q[i] 数组
找到 q[i] 当中第一个严格小于 a[i] 的数(设其下标为 idx),之后我们更新 q[idx] 与 len
最后的 len 便是最长上升子序列的长度
完整代码:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], q[N];//q[i]表示长度为i的上升子序列的结尾数字
int n;
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
int len = 0;
q[0] = -1e9;//避免出界
for(int i = 1; i <= n; i++)
{
int l = 0, r = len;
while(l < r)//二分,找到q[i]中第一个比a[i]小的数
{
int mid = l + r + 1 >> 1;
if(q[mid] < a[i]) l = mid;
else r = mid - 1;
}
q[l + 1] = a[i];//对q[i]和len进行更新
len = max(len, l + 1);
}
cout << len << endl;
return 0;
}