最长上升子序列(三)

last modify

问题简述

给定数组,返回字典序最小的最长上升子序列;

最长上升子序列(三)_牛客题霸_牛客网

思路:动态规划

  • 为了返回字典序最小的 LIS,本题需要结合两种 dp 状态;

    • dp_min[i] 表示长度为 (i+1) 的 LIS 结尾的最小值;

    • dp_len[i] 表示以 arr[i] 结尾的 LIS 的长度;

    这两种状态都可以用来求 LIS 的长度,前者的时间复杂度为 $O(n\log n)$,后者为 $O(n^2)$

  • 得到这两个状态序列后就可以来计算具体的 LIS 了;下面举例说明如何使用这两个状态来还原 LIS;

    arr:    [1,2,8,6,4]
    dp_len: [1,2,3,3,3]
    dp_min: [1,2,4]
    # 这里省略了这两个状态序列的生成过程,
    # 因为 dp_len 可以在计算 dp_min 的过程中一起获得,因此时间复杂度依然是 `O(NlogN)`
    
    初始化:
        cnt = len(dp_min) # LIS 的长度
        ret = [0] * cnt  # 记录 LIS
    
    然后逆序遍历 dp_len
    当 dp_len[i] == cnt 时,将 ret[cnt - 1] 赋值为 arr[i],同时 cnt -= 1
    
    为什么要逆序遍历?
        举个例子,arr 结尾的三个数,其最大的 LIS 长度都是 3,但其中 4 是最小的,
        因为如果它不是最小的,意味着它对应的 LIS 长度就应该大于 3 了
Python:递归写法
Python:迭代写法(推荐)

Last updated