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 个数。