【中等】Leetcode-最长上升子序列///动态规划///二分查找优化

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

思路:
最长上升子序列动态规划详解

如图:1是长度为1的子序列,1是末尾元素;2->3是长度为2的子序列,3是末尾元素(为什么不选2->5呢,因为3比5小,后面可以接相比5更多的数);2->3->4是长度为3的子序列,4是末尾元素(为什么不选7同上);最后2->5->7->101或2->3->7->101都是长度为4的子序列,其中101是末尾元素。

讲解:

下段摘录自上述链接:

  • 假如我们要在里面新增一个元素 X,希望找出插入 X 之后的最长子序列。
  • 结论一指出,我们需要在当前允许插入的最长子序列之后添加元素。
  • 于是,我们可以依次检查序列长度 = 1,2,3,4 的递增子序列,然后找出满足尾数 < X 的序列中 最长的那个。
  • 我们发现,对每一个序列长度 l,只需要检查图中的每一列的最小值(绿色的元素)是否 < X 即可。如果绿色的元素 < X,表明长度为 l 的递增子序列后可添加元素 X。
  • 因此,我们有 结论二:我们只需要维护 长度为 l 的递增子序列的 最小结尾数字。
  • 这样,我们得到了一个数组[1, 3, 4, 101]。这就是官方题解中的动态规划 dp 数组。
  • 值得注意的是,[1, 3, 4, 101] 不是任何一个实际存在于数组的递增子序列!!
  • 实际上,[1, 3, 4, 101] 中的每一个数字都隐含了前述图中的 一条路径,并且 其结尾数字在当前层最小。换句话说,[1, 3, 4, 101] 中每一个数字的实际意义是,长度为 i(下标) + 1 的递增子序列末尾的最小数字。(比如1的下标是0,0+1就是1,即1是长度为1的子序列的末尾元素;3的下标是1,1+1是2,即3是长度为2的子序列的末尾元素)
  • 对于这样的 dp 数组,我们有 结论3:dp数组一定是 严格递增 的。因为 dp[i] 为 长度为 i+1 的递增子序列末尾的最小数字,而当 i >= 1时,长度为 i+1 的递增子序列一定是由长度为 i 的递增子序列添加元素而来,如果长度为 i 的递增子序列的 最小尾数 为 X,则添加的元素一定 > X。

实现算法的细节

最简单的实现方式,当插入新元素 X 时,我们从 1 逐个枚举现有递增子序列的长度,直到找到最大可添加元素 X 的长度。与此同时,维护每个长度 l 的最小尾数:
比如前述序列 [10, 9, 2, 5, 3, 7, 101, 4, 1],已构造 dp 数组[1, 3, 4, 101],要添加 “6”。

长度 l = 1 时,长度为 1 的递增子序列末尾的最小数字为 1,6 > 1,可以添加。
l = 2 时,6 > 3,可以添加。
l = 3 时,6 > 4,可以添加。
l = 4 时,6 < 101,不可添加。
因此,以 “6” 为结尾的递增子序列最长为 3 + 1 = 4。
另外,此时,长度为 4 的递增子序列的最小尾数变成了 “6”。因此修改 “101” -> “6”。数组变为 [1, 3, 4, 6]。
如果要添加 “102”呢?

由于 “102” > “101”,因此 “102” 可以在长度为 4 的子序列后添加,递增子序列的最大长度变成了 5。
由于长度为 5 的递增子序列的尾数只有 “102”,故最小尾数也是 “102”,直接在数组后添加 “102” 即可。
lower_bound()函数详解

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int> minnums;
        for(int v : nums)
        {
            if(!minnums.size() || v > minnums.back()) 
                minnums.push_back(v); 
                //大于最后一位的直接加在数组后面,就像上面的的102
            else
                *lower_bound(minnums.begin(), minnums.end(), v) = v;
                //否则用二分查找找出第一个大于或等于v的元素,然后替换它
                //就像上面的6替换第一个大于它的101
                //注意lower_bound()函数返回的是地址
        }
        return minnums.size();
    }
};

作者:newhar
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/yi-bu-yi-bu-tui-dao-chu-guan-fang-zui-you-jie-fa-x/
来源:力扣(LeetCode)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值