最长上升子序列的优化之二分查找问题
解题思路
使用二分来对朴素版动态规划进行优化
当这个数a[i]比当前f最后一个数f[cnt]还要大时,那么这个数就符合条件f[cnt++] = a[i]
否则 就在f数组里面找第一个比a[i]大的数, 把a[i] 替换给这个位置
毕竟1 5 6 和1 4 6 总是1 4 6 可能性更高一些
比如 2 6 4 5 3
第一次 f: 2 2 > 6
第二次 f: 2 6 4 < 6 f[1] = 4
第三次 f: 2 4 5 > 4
第四次 f: 2 4 5 3 < 5 f[1] = 3
第五次 f: 2 3 5 结束
关于lower_bound和upper_bound函数
使用方法:lower_bound(f, f + n, x); x是需要查找的数
lower_bound返回的是第一个大于等于x的迭代器, 如果想要计算下标,在后面减去数组的首地址就可以(参考下面代码)
因为这个题的f[i]是严格递增的, 也就是说不会有两个数是相同的, 第一个大于等于x的数就是第一个大于x的数
upper_bound返回的是第一个大于x 的迭代器,计算下标也是减去数组首地址
使用while实现lower_bound()函数
x;//大于等于寻找的值的最小下标 找不到会返回数组长度 + 1
int len = 7;
// 0 1 2 3 4 5
int a[] = {1, 2, 3, 3, 3, 4, 5};
int l = 0, r = len;
while(l <= r)
{
int mid = l + r >> 1;
if(a[mid] < 3)
l = mid + 1;
else
r = mid - 1;
}
//使用lower_bound()
int t = lower_bound(a, a + n, x) - a;
使用while()实现upper_bound()
x;//大于寻找的值的下标 找不到返回数组长度 + 1
int len = 7;
// 0 1 2 3 4 5
int a[] = {1, 2, 3, 3, 3, 4, 5};
int l = 0, r = len;
while(l <= r)
{
int mid = l + r >> 1;
if(a[mid] <= 3)
l = mid + 1;
else
r = mid - 1;
}
//使用upper_bound()
int t = upper_bound(a, a + n, x) - a;
附代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
int f[N], a[N];//最长递增子序列 数据输入
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; i ++)cin >> a[i];
int cnt = 0;
f[cnt++] = a[1];
for(int i = 2; i <= n; i ++)
{
if(a[i] > f[cnt - 1])f[cnt ++] = a[i];
else
{
int t = lower_bound(f, f + cnt, a[i]) - f;
f[t] = a[i];
}
}
cout << cnt << endl;
return 0;
}

浙公网安备 33010602011771号