插入区间

46 阅读1分钟

57. 插入区间 - 力扣(LeetCode)

给你一个 无重叠的 按照区间起始端点排序的区间列表。

在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。

示例  1:

输入: intervals = [[1,3],[6,9]], newInterval = [2,5]
输出: [[1,5],[6,9]]

示例 2:

输入: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出: [[1,2],[3,10],[12,16]]
解释: 这是因为新的区间 [4,8][3,5],[6,7],[8,10]  重叠。

示例 3:

输入: intervals = [], newInterval = [5,7]
输出: [[5,7]]

示例 4:

输入: intervals = [[1,5]], newInterval = [2,3]
输出: [[1,5]]

示例 5:

输入: intervals = [[1,5]], newInterval = [2,7]
输出: [[1,7]]

提示:

  • 0 <= intervals.length <= 10^4
  • intervals[i].length == 2
  • 0 <= intervals[i][0] <= intervals[i][1] <= 10^5
  • intervals 根据 intervals[i][0]升序 排列
  • newInterval.length == 2
  • 0 <= newInterval[0] <= newInterval[1] <= 10^5

思路

对于区间 s1 = [l1,r1]和区间 s2 = [l2,r2], 如果他们没有交集,满足 r1<l2,此时 s1s2 的右侧,或 r2<l1,此时 s1s2 的左侧,如果两个条件都不满足,则 s1s2 必相交,合并区间为 [min(l1, l2), max(r1, r2)]

我们遍历 intervals, 找到 i,满足 intervals[i][1] >= newInterval[0] , 判断 intervals[i] 是否相交,

  • 如果相交,合并区间,继续判断是否和下一个区间相交,直到不相交为止,删除原先相交的区间,并插入合并后的区间 。
  • 如果不相交,在 intervals[i] 之前插入 newInterval

在查找i时,由于区间是有序的,可以使用二分查找加快查找速度。

解题

/**
 * @param {number[][]} intervals
 * @param {number[]} newInterval
 * @return {number[][]}
 */
var insert = function (intervals, newInterval) {
  const bf = (num, key) => {
    let l = 0;
    let r = intervals.length - 1;
    while (l <= r) {
      const mid = (l + r) >> 1;
      if (intervals[mid][key] === num) {
        r = mid;
        break;
      } else if (intervals[mid][key] < num) {
        l = mid + 1;
      } else {
        r = mid - 1;
      }
    }
    return r;
  };
  let l = bf(newInterval[0], 0);
  let r = bf(newInterval[1], 1);

  if (l >= 0 && intervals[l][1] >= newInterval[0]) {
    newInterval[0] = intervals[l][0];
  } else {
    l++;
  }

  if (r < intervals.length - 1 && intervals[r + 1][0] <= newInterval[1]) {
    newInterval[1] = intervals[r + 1][1];
    r++;
  }
  intervals.splice(l, r - l + 1, newInterval);
  return intervals;
};

module.exports = insert;