(整理) 最长上升序列 LIS问题详解

今天遇到了几个LIS的题目, 整得我焦头烂额, 不过终于算是搞懂了, 下面分享给大家, 并推荐几篇讲的非常好的博客, 以及几道非常好的练习题做

动态规划

首当其冲的方法当然非动态规划莫属, 这种方法也是非常容易理解的一种方法, 首先定义一个数组f[], f[i]的值代表以a[i]结尾的最长上升序列的长度, 状态转移的核心代码如下所示
for (int i = 1; i <= n; i++) {
    for (int j = 0; j < i; j++) {
        //如果a[i]比a[j]大, 那么把a[i]接在以a[j]结尾的序列后面当然就更长啦
        if (a[i] > a[j]) {
            a[i] = max(a[i], a[j] + 1);
        }
    }
    //ans保存最终的答案
    ans = max(ans, a[i]);
}
复制代码

利用了upper_bound的二分查找的O(nlogn)的算法

这个算法有点难以理解, 反正蒟蒻我花了好久才搞懂, 感觉这个有点像贪心算法, 正确性不会证明, 我们想要得到一个最长的上升序列, 那么我们肯定希望长度越长越好, 结尾元素越小越好(因为越小的话后面能接的元素当然就越多啦).

实现的方式


首先我们构造一个栈s[], 这个栈的长度保证是最优解的长度, 但里面的元素值可就不保证喽, 原因下面我会交代, 就是这里卡了我好久
如果a[i] >= s[len],说明a[i]可以接在s后面(而整个s还是有序的),那就简单粗暴地把a[i]丟进s, 否则的话

那么就说明这个比栈顶元素小的元素k接不上去, 但可能含这个元素的上升序列会更优, 毕竟它更小, 能接在它后面的元素会更多嘛, 于是我们就在栈s中利用upper_bound函数去二分寻找第一个大于k的元素, 假设它是y, 然后用k替换y. 看到这, 您可能会很疑惑, 为什么可以替换???

这里解释原因, 如果y在序列的末尾, 那么把它给踢了当然没毛病, 很容易想, 但是如果y不在末尾呢? 这时把它踢了对最优解的长度是没有影响的, 因为你替换后得到的序列的长度不会小于替换前

博客推荐

接下来推荐几篇不错的博客帮助大家消化一下
算法题解:经典的动态规划问题——最长递增子序列(一)
算法题解:经典的动态规划问题——最长递增子序列(二)
题解 P1020 【导弹拦截】
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值