• Leetcode 673 | 300


    300 的最基础做法还是很好理解的。

    对于nums[i],我们记录下它可以和前面的元素组成多长的最长子序列。

    例如nums = [1, 2, 5, 4, x, ...],

    我们就得到对应的记录数组 maxlen = [1, 2, 2, 3, y, ...]。

    那么此时我们只需要在 1 ~ i-1 的数中取所有小于 x 的数,

    然后从中挑一个maxlen值最大的,给 y 加上就行了。

    300 的进阶做法就是,我维护一个数组 d,然后我:

    1. nums[i] > d[len-1],则 d[len] = nums[i]。即把当前遇到的最大的数放到 d 的末尾

    2. 否则,将 d 中第一个比 nums[i] 大的数替换为 nums[i]

    这个算法有点别扭,但是想清楚了还是挺简单的。

    对于 [2, 4, 6, 8],d =[2, 4, 6, 8]

    现在我遇到了一个 5, 我就把 d 改成 [2, 4, 5, 8]

    d 中的元素不是真实的最长上升子序列,但是我们的维护法则 1 保证了,如果一个数放在 len 的位置,那么在它之前一定有 len - 1 长度的上升子序列。

    考虑 [2, 4, 6, 8, 999, 10, 12]

    如果我们没有维护法则2,那么在遇到 999 后,d就无法继续增长了

    维护法则2的存在,就是挑选出同等长度的上升子序列中,末尾数值最小的一个

    这样的话往后累加时,就能尽可能地利用数字。

    否则,999 无法替换成 10,那么遇到 12 的时候我们也没法往 d 里面加了

    现在看 673。之前我们在替换的时候,是把数值扔掉了。

    现在我们把它保留下来,相当于现在 d 被我们改造成一个指针链表那样的数据结构,一个数组的槽指向一个链表。

    每次插入链表,我们就计算当前元素所能构成的LIS的个数。

    我觉得下标说得有点麻烦,举个例子吧

    [...] [...] [...] [12->15->18->25] [33->40] [...] ...

    这是我们记录下的历史信息的数组,如果用300的视角来看,就是[x, x, x, 12, 33, ...]

    现在假设我们遇到了 20,那现在我们要替换掉的就是 33

    [...] [...] [...] [12->15->18->25] [20 -> 33->40] [...] ...

    然后,在其前面一位,有三个数比 20 小,分别是 12, 15, 18

    那么我们就累加 12, 15, 18 的LIS个数,再加上 1,就是 【20】这个新插入数的 LIS 个数。

  • 相关阅读:
    frame、window和dialog区别
    wxWidgets窗口类型
    C++中类与结构体的区别
    c++中explicit关键字用法
    解决error C2011: 'fd_set' : 'struct' type redefinition的方法
    jrtplib源码分析 第一篇 jthread的编译与分析
    详解大端模式和小端模式
    C++——重点复习
    Linux组件封装(九)——EchoLib的一些简单综合
    Linux组件封装(八)——Socket的封装
  • 原文地址:https://www.cnblogs.com/KakagouLT/p/15313341.html
Copyright © 2020-2023  润新知