zhangdizhangdi

300.最长递增子序列 🌟

题目

LeetCode 中等

题目

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。
例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

示例:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

输入:nums = [0,1,0,3,2,3]
输出:4

输入:nums = [7,7,7,7,7,7,7]
输出:1

题解

方法:动态规划

DP O(n2) O(n)

js
function lengthOfLIS(nums) {
  const len = nums.length
  if (len === 0) return 0
  if (len === 1) return 1
  let maxLen = 1
  const dp = Array(len).fill(1)
  for (let i = 1; i < len; i++) {
    for (let j = 0; j < i; j++) {
      console.log(nums[i], nums[j])

      //与前面元素比较
      if (nums[i] > nums[j]) {
        //碰到小的,dp[j]+1
        dp[i] = Math.max(dp[j] + 1, dp[i])
        maxLen = Math.max(maxLen, dp[i])
      }
    }

    console.log('------')
  }

  console.log('dp:', dp)

  return maxLen
}

// const array = [10, 9, 2, 5, 3, 7, 101, 1, 4]
// const array = [10, 9, 2, 5, 3, 4]
const array = [3, 5, 6, 2, 5, 4]
console.log('🌰', lengthOfLIS(array))
执行结果
5 3
------
6 3
6 5
------
2 3
2 5
2 6
------
5 3
5 5
5 6
5 2
------
4 3
4 5
4 6
4 2
4 5
------
dp: [ 1, 2, 3, 1, 2, 2 ]
🌰 3

方法:贪心 + 二分查找

贪心 二分查找 O(nlogn) O(n)

❗️ 得到的 tail 并不一定是最后正确的序列,只能保证 length 正确。

js
function lengthOfLISBinarySearch(nums) {
  const len = nums.length
  if (len <= 1) {
    return len
  }
  const tail = [nums[0]]
  for (let i = 0; i < len; i++) {
    const num = nums[i]

    console.log('-------')
    console.log(num)

    if (num > tail[tail.length - 1]) {
      //当nums中的元素比tail中的最后一个大时,直接push
      tail.push(num)
    } else {
      let li = 0 //左下标
      let ri = tail.length - 1 //右下标
      while (li < ri) {
        let mi = (li + ri) >> 1 //中间下标

        console.log('li', li, 'ri', ri, 'mi', mi, '| tailNum', tail[mi])

        if (tail[mi] < num) {
          li = mi + 1
        } else {
          ri = mi
        }
      }
      tail[li] = num //将 num 放置到合适的位置,此时前面的元素都比 num 小
    }

    console.log(`第${i + 1}轮:`, JSON.stringify(tail))
  }
  return tail.length
}

const array2 = [3, 5, 6, 2, 5, 4, 19, 5, 6, 7, 12]
console.log('🌰', lengthOfLISBinarySearch(array2))
执行结果
-------
3
第1轮: [3]
-------
5
第2轮: [3,5]
-------
6
第3轮: [3,5,6]
-------
2
li 0 ri 2 mi 1 | tailNum 5
li 0 ri 1 mi 0 | tailNum 3
第4轮: [2,5,6]
-------
5
li 0 ri 2 mi 1 | tailNum 5
li 0 ri 1 mi 0 | tailNum 2
第5轮: [2,5,6]
-------
4
li 0 ri 2 mi 1 | tailNum 5
li 0 ri 1 mi 0 | tailNum 2
第6轮: [2,4,6]
-------
19
第7轮: [2,4,6,19]
-------
5
li 0 ri 3 mi 1 | tailNum 4
li 2 ri 3 mi 2 | tailNum 6
第8轮: [2,4,5,19]
-------
6
li 0 ri 3 mi 1 | tailNum 4
li 2 ri 3 mi 2 | tailNum 5
第9轮: [2,4,5,6]
-------
7
第10轮: [2,4,5,6,7]
-------
12
第11轮: [2,4,5,6,7,12]
🌰 6