前端算法面试必刷题系列[21]

431 阅读4分钟

这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。

36. 合并区间 (merge-intervals)

标签

  • 排序简化思路
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

合并给的多个区间,区间有重叠的要进行区间合并。

基本思路

  1. 先按照区间起点进行排序。
  2. 然后从区间起点小的开始扫描。
  3. 依次合并每个有重叠的区间。

看代码中注释我感觉足够了,比较清晰简单

写法实现

var merge = function(intervals) {
  const [mergedRes, len] = [[], intervals.length];
  // 按照左端点排序,善用sort,并取开头第一个区间,作为开始比较的数组
  intervals.sort((a, b) => a[0] - b[0]);
  let start = intervals[0];
  // 然后从区间起点小的开始扫描,依次合并每个有重叠的区间。
  for (let i = 1; i < intervals.length; i++) {
    // 取当前区间
    let curInterval = intervals[i]
    // 如果发现开始节点右端大于当前节点左端,则必然有重合部分
    if (start[1] >= curInterval[0]) {
      // 那么就把右边端点设置成当前较大的右边界
      start[1] = Math.max(start[1], curInterval[1]);
    } else {
      // 不重合,就是断了,那么把开始的节点推入结果数组
      mergedRes.push(start)
      start = curInterval
    }
  }

  // 最后别忘了当前节点需要推送
  mergedRes.push(start);
  return mergedRes
};

let intervals = [[3,4],[1,3],[2,6],[8,10],[15,18]]

console.log(merge(intervals))

37. 插入区间 (insert-interval)

标签

  • 文字理解
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

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

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

基本思路

  1. 新区间插到总得区间列表中。
  2. 跟上题一模一样,合并区间步骤。所以代码也只要改2行就行。

写法实现

var insert = function(intervals, newInterval) {
  // 插入新的区间
  intervals.push(newInterval)
  // 注意取新区间长度,之后跟上面一题一模一样,没有区别,简单吗
  const [mergedRes, len] = [[], intervals.length];
  // 按照左端点排序,善用sort,并取开头第一个区间,作为开始比较的数组
  intervals.sort((a, b) => a[0] - b[0]);
  let start = intervals[0];
  // 然后从区间起点小的开始扫描,依次合并每个有重叠的区间。
  for (let i = 1; i < intervals.length; i++) {
    // 取当前区间
    let curInterval = intervals[i]
    // 如果发现开始节点右端大于当前节点左端,则必然有重合部分
    if (start[1] >= curInterval[0]) {
      // 那么就把右边端点设置成当前较大的右边界
      start[1] = Math.max(start[1], curInterval[1]);
    } else {
      // 不重合,就是断了,那么把开始的节点推入结果数组
      mergedRes.push(start)
      start = curInterval
    }
  }

  // 最后别忘了当前节点需要推送
  mergedRes.push(start);
  return mergedRes
};

let intervals = [[1,3],[6,9]], newInterval = [2,5]

console.log(insert(intervals, newInterval))

38. 区间列表的交集 (interval-list-intersections)

标签

  • 双指针
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给定两个由一些 闭区间 组成的列表,firstList 和 secondList ,其中 firstList[i] = [starti, endi] 而 secondList[j] = [startj, endj] 。每个区间列表都是成对 不相交 的,并且 已经排序 。

返回这 两个区间列表的交集 。如图

image.png

基本思路

  1. 一般涉及到多个区间的交集、合并、覆盖等问题的时候,首先应将各区间按左端点升序排列,这道题已经给排好序了。用双指针
  2. 对于两个闭区间[a1, a2][b1, b2],当a1 > b2 or b1 > a2时两个区间没有交集
  3. 分别扫描 A、B 数组,当遍历到的两个区间有交集时,交集为[max(a1, b1), min(a2, b2)]
  4. 交替进行指针移动,当a2<b2时,移动j指针,否则移动i指针,直至指针越界,得到由交集区间组成的数组。

写法实现

var intervalIntersection = function(firstList, secondList) {
  const [intersectionRes, Alen, Blen] = [[], firstList.length, secondList.length];
  // 双指针, i 是 firstList(A) 的开头,j 是 secondList(B) 的开头
  let i = 0, j = 0;
  while (i < Alen && j < Blen) {
    // start, end 代表交集区间的左右两端
    // 例如 [1, 5] [2, 7] 交集是 [2, 5]
    // 交集区间的左端,取它们左端点的较大者 2
    // 交集区间的右端,取它们右端点的较小者 5
    let start = Math.max(firstList[i][0], secondList[j][0])
    let end = Math.min(firstList[i][1], secondList[j][1])
    // 如果这样就形成了交集区间, 推入结果数组
    if (start <= end) {
      intersectionRes.push([start, end])
    }
    // 交替移动指针,右边界小的先右移
    if (firstList[i][1] < secondList[j][1]) {
      i++
    } else {
      j++
    }
  }
  return intersectionRes
};

let firstList = [[1,7]], secondList = [[3,10]]

console.log(intervalIntersection(firstList, secondList))

总结

今天掌握区间列表的各种操作,求并集,交集,覆盖等问题,我们首先根据左端点排序,再依次扫描或双指针处理就ok了

另外向大家着重推荐下这位大哥的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列

今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 搜索我的微信号infinity_9368,可以聊天说地 加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我 presious tower shock the rever monster,我看到就通过,暗号对不上不加哈,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧

参考