LIS 的 n*log 算法 ———二分维护

2 篇文章 0 订阅

upper_bound只会替换让留在数组里的最长递增子序列尽可能小
由于upper查出来的结果下标是那个可以插入这个值得最后一个元素
所以他会把大的数变成小的数

upper将可以替换成新元素的元素替换成更小的
将不能替换的元素 大的元素直接放在最后面
很神奇

你会发现 这个问题
通过一个二分就能解决
如何解决的呢
我们要在vector中维护一个递增序列
如何维护
那就是每当我们遍历过程中拿到一个元素
考虑如果这个元素比我们维护的最大递增数列的最大值还要大
就插在最后
如果比那个序列的最大值小
就需要在序列中
找到一个地方 放下这个值 使得我们整个序列的长度还是没变
但是能够替换某个元素使得这个序列中的某些元素变小
从而达到当我新来一个元素时能够尽可能插入进去
扩增LIS的长度的效果
因为在一个数组X中
X中的递增序列可能有多个
其中一定是最小的那个序列(对应元素尽可能的小)是LIS
比如在1 2 100 2 2中
LIS 1 2 2 2
那么 如果我们维护的是 1 2 100
此时就得不到最终的LIS 由于不是严格递增
所以我们要选择upperbound 要在维护的数列中选择
插入上界 跳过相等的元素 用2替换100使得序列尽可能长
而如果题目要求的是 严格递增
我们拿到一个新元素小于维护数列的最大元素时
就需要lowerbound插进去因为 我们要替换的是相等的元素
不过如果原来的序列中并没有与插入元素相等的元素
我们用lower_bound仍然会替换得到的序列会更小

**所以LIS问题
非严格递增 用upperbound维护 以为每次遇到一个相等的元素我们可以延长他相等的长度
从而增大LIS的长度 (注意虽然这里可以增大LSI的长度 但我们得到的并非是真正的LIS
我们只是得到了长度 比如对于1 2 3 4 5 2 2 这个序列 如果我们用uper维护
那么到我我们得到的序列是 1 2 3 4 5 继续处理我们得到了 1 2 2 2 5 虽然在原始中并不存在这个序列
但是他符合我们最长的要求 如果后面有更多的2 也就是可以把前面的大数全部覆盖
例如 我们得到了1 2 3 4 5 2 2 2 -〉我们得到最长的序列就是 1 2 2 2 2 假如原序列后面有个3
我们正好把他插入进去 得到名副其实的LIS 但如果我们不用upper维护 我们就得不到这个长度
所以虽然辅助数组中存的不是真正的LIS 但我们维护的策略是尽可能得到LIS的长度而非LIS
假如数列中最大值后面的元素数量不足以覆盖最大值 那么我们就算是LIS 依旧是在真正的LIS上进行操作
不会对真正的LIS长度造成影响
如果数列最大值后面的元素足够多了覆盖了最大值而且后面还能继续增加长度
那么我们这里的覆盖就是合理的 为了得到LIS的最大长度 这是我们的唯一选择

严格递增 用lowerbound插入比维护数组小的元素(
如上面的例子 我们用upper维护得到的是非严格递增的
那么用lower维护 遇到序列里已经存在的值 我们lower一下并没有任何实质性改变
所以用lower维护出来的一定是严格递增的最大值

时间复杂度O(nlogn)**

所以用二分去构造LIS的原因在于 二分插入的过程就是我们自己手工找出LIS的过程
遇到更大的值就插入LIS 否则就不断替换我们找到的数串以找到更长的LIS

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值