这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。
36. 合并区间 (merge-intervals)
标签
- 排序简化思路
- 中等
题目
这里不贴题了,leetcode打开就行,题目大意:
合并给的多个区间,区间有重叠的要进行区间合并。
基本思路
- 先按照区间起点进行排序。
- 然后从区间起点小的开始扫描。
- 依次合并每个有重叠的区间。
看代码中注释我感觉足够了,比较清晰简单
写法实现
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打开就行,题目大意:
给你一个 无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
基本思路
- 新区间插到总得区间列表中。
- 跟上题一模一样,合并区间步骤。所以代码也只要改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打开就行,题目大意:
给定两个由一些 闭区间 组成的列表,firstList 和 secondList ,其中 firstList[i] = [starti, endi] 而 secondList[j] = [startj, endj] 。每个区间列表都是成对 不相交 的,并且 已经排序 。
返回这 两个区间列表的交集 。如图
基本思路
- 一般涉及到多个区间的
交集、合并、覆盖
等问题的时候,首先应将各区间按左端点升序排列,这道题已经给排好序了。用双指针 - 对于两个闭区间
[a1, a2]
和[b1, b2]
,当a1 > b2 or b1 > a2
时两个区间没有交集
。 - 分别扫描 A、B 数组,当遍历到的两个区间有交集时,交集为
[max(a1, b1), min(a2, b2)]
。 - 交替进行指针移动,当
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
,我看到就通过,暗号对不上不加哈,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧