sl1673495 / leetcode-javascript

:beers: 喝杯小酒,一起做题。前端攻城狮从零入门算法的宝藏题库,根据知名算法老师的经验总结了 100+ 道 LeetCode 力扣的经典题型 JavaScript 题解和思路。已按题目类型分 label,一起加油。
2.08k stars 344 forks source link

无重叠区间-435 #90

Open sl1673495 opened 4 years ago

sl1673495 commented 4 years ago

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。

注意:

可以认为区间的终点总是大于它的起点。 区间 [1,2][2,3] 的边界相互“接触”,但没有相互重叠。

示例 1:

输入: [ [1,2], [2,3], [3,4], [1,3] ]

输出: 1

解释: 移除 [1,3] 后,剩下的区间没有重叠。
示例 2:

输入: [ [1,2], [1,2], [1,2] ]

输出: 2

解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
示例 3:

输入: [ [1,2], [2,3] ]

输出: 0

解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/non-overlapping-intervals 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

本题可以转化成最长上升子序列-300相同的问题。

先把区间数组按照每个数组的开头项排序,然后用 dp[i] 表示从 [0, i] 能构成的最长的无重叠区间的个数,利用上升子序列的同样思路去求解即可。对于每个区间intervals[i],都从 0 ~ j 去逐个遍历之前的项,一旦发现 i.start >= j.end 说明这两者构成非重叠区间,那么就把 max 值尝试更新为 dp[j] + 1

最后找出所有 dp 项中的最大值,也就是最长的非重叠区间长度,用区间的总长度减去这个最长长度,得出的就是需要移除掉的数组长度。

/**
 * @param {number[][]} intervals
 * @return {number}
 */
let eraseOverlapIntervals = function (intervals) {
  let n = intervals.length
  if (!n) {
    return 0
  }

  // 按照起始点排序
  intervals.sort((a, b) => a[0] - b[0])

  // dp[i] 表示从 [0, i] 能构成的最长的无重叠区间的个数
  let dp = []
  dp[0] = 1

  for (let i = 1; i < n; i++) {
    let max = 1
    let [curStart] = intervals[i]
    for (let j = 0; j < i; j++) {
      let [prevStart, prevEnd] = intervals[j]
      if (prevEnd <= curStart) {
        max = Math.max(max, dp[j] + 1)
      }
    }
    dp[i] = max
  }

  return n - Math.max(...dp)
}