最长上升子序列LIS(dp)

分析

最长上升子序列:对于一个序列A[],找出一个子序列x[], 使xi < xj(i < j),xi
和xj不一定连续,求最长的一个子序列
O(n^2)做法:
定义状态:d[i]为当前元素作为最后一个元素的LIS长度
转移方程:d[i] = max{d[j] + 1 | i > j && a[i] > a[j]};
目标:max(d[i])
状态:O(n), 转移O(n),时间复杂度O(n ^ 2)
O(nlgn)做法;
思路:对于具有相同d[i]的两个元素a和b,并且a < b,那么每次只保留a一定不会丢失最优解(假设只保留了a, 设下一次选择的元素使x,如果满足x > a, 那么LIS里面可新加入x。但是若只保留了b, 设下一次选择的元素为x,且满足x > a,但是x < b,这时候LIS里面不会加入x,并且此时对于x,得到的不是以x为最后一个元素的LIS)
因此对于具有相同d[i]的任意两个元素a和b,我们只保留小的那个元素。设g[i]保存的是当前d值为i的最小元素值。那么每次新插入一个元素x,只需要二分查找该元素可插入在g[]中的位置,并且更新g[]数组即可
时间复杂度O(nlgn)

代码

//初始化g[],g[]下标从1开始计数,因为LIS的最小长度为1
for (int i = 1; i <= n; i++) g[i] = INF;
for (int i = 0; i < n; i++) {
    //找到当前元素A[i]可在g数组中插入的位置
    //二分查找,时间复杂度O(lgn)
    int k = lower_bound(g + 1, g + 1 + n, A[i]) - g;
    //更新g[]
    g[k] = A[i];
    //更新d[]
    d[i] = k;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值