300 最长上升子序列

题目:

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

分析:

题目中并没有求最长连续上升子序列,所以子序列只是保持相对位置的元素集合。

那么定义 dp[i] 表示包含元素nums[i]的最长上升序列的长度,那么两层遍历即可得到下面的递推公式:

当 0 <= j < i && nums[i] > nums[j] 时
dp[i] = max(dp[j]) + 1

初始状态为 dp[0] = 1,即一个元素组成的上升序列。

// date 2023/11/09
func lengthOfLIS(nums []int) int {
    if len(nums) == 0 {
        return 0
    }
    res := 1
    n := len(nums)

    dp := make([]int, n)
    dp[0] = 1

    for i := 1; i < n; i++ {
        dpj_max := 0
        for j := 0; j < i; j++ {
            if nums[i] > nums[j] {
                dpj_max = max(dpj_max, dp[j])
            }
        }
        dp[i] = dpj_max + 1

        res = max(res, dp[i])
    }

    return res
}

func max(x, y int) int {
    if x > y {
        return x
    }
    return y
}

算法2:

// date 2020/03/16
func lengthOfLIS(nums []int) int {
  if len(nums) == 0 { return 0}
  n := len(nums)
  lis := make([]int, 0, n)
  lis = append(lis, nums[0])
  for i := 1; i < n; i++ {
    // 在lis数组找到第一个比nums[i]大的元素,并替换它,否则进行追加
    m := len(lis)
    // nums[i] > lis[m-1]
    // nums[i] 直接参与最长上升序列
    if nums[i] > lis[m-1] {
      lis = append(lis, nums[i])
      continue
    }
    // 替换的必要性
    // 1. 保证 nums[i] 有机会参与最长上升序列,为后面更大的值剔除障碍
    // 2. 因为不要求连续性,lis 中的大值没有意义,替换相对于变相删除
    for j := 0; j < m; j++ {
      if nums[i] <= lis[j] {
        lis[j] = nums[i]
        break
      }
    }
  }
  return len(lis)
}

最后更新于