题目描述
思路解析动画文字版
核心两步:① 重叠区间 = [起点取大, 终点取小],lo≤hi 才算数;② 终点更小的那个指针前进。
开始:指针 i 指向 A 的第 0 个区间(高亮格),指针 j 指向 B 的第 0 个区间(侧栏高亮行)。答案先是空的。
比较 A[0]=[0,2] 和 B[0]=[1,5]:重叠左端 lo 取两起点的大者=1,右端 hi 取两终点的小者=2。
因为 lo=1 不大于 hi=2,这段 [1,2] 是真实重叠,收进答案。
A[0] 的终点 2 比 B 的终点 5 小,它对后面再没贡献,所以 i 前进一格到 1。
比较 A[1]=[5,10] 和 B[0]=[1,5]:重叠左端 lo 取两起点的大者=5,右端 hi 取两终点的小者=5。
因为 lo=5 不大于 hi=5,这段 [5,5] 是真实重叠,收进答案。
B[0] 的终点 5 比 A[1] 的终点 10 小,它对后面再没贡献,所以 j 前进一格到 1(A 的指针不动)。
比较 A[1]=[5,10] 和 B[1]=[8,12]:重叠左端 lo 取两起点的大者=8,右端 hi 取两终点的小者=10。
因为 lo=8 不大于 hi=10,这段 [8,10] 是真实重叠,收进答案。
A[1] 的终点 10 比 B 的终点 12 小,它对后面再没贡献,所以 i 前进一格到 2。
比较 A[2]=[13,23] 和 B[1]=[8,12]:重叠左端 lo 取两起点的大者=13,右端 hi 取两终点的小者=12。
因为 lo=13 大于 hi=12,A[2] 和 B[1] 没有公共部分,什么都不收。
B[1] 的终点 12 比 A[2] 的终点 23 小,它对后面再没贡献,所以 j 前进一格到 2(A 的指针不动)。
比较 A[2]=[13,23] 和 B[2]=[15,24]:重叠左端 lo 取两起点的大者=15,右端 hi 取两终点的小者=23。
因为 lo=15 不大于 hi=23,这段 [15,23] 是真实重叠,收进答案。
A[2] 的终点 23 比 B 的终点 24 小,它对后面再没贡献,所以 i 前进一格到 3。
比较 A[3]=[24,25] 和 B[2]=[15,24]:重叠左端 lo 取两起点的大者=24,右端 hi 取两终点的小者=24。
因为 lo=24 不大于 hi=24,这段 [24,24] 是真实重叠,收进答案。
B[2] 的终点 24 比 A[3] 的终点 25 小,它对后面再没贡献,所以 j 前进一格到 3(A 的指针不动)。
比较 A[3]=[24,25] 和 B[3]=[25,26]:重叠左端 lo 取两起点的大者=25,右端 hi 取两终点的小者=25。
因为 lo=25 不大于 hi=25,这段 [25,25] 是真实重叠,收进答案。
A[3] 的终点 25 比 B 的终点 26 小,它对后面再没贡献,所以 i 前进一格到 4。
其中一个列表的指针已走到头,循环结束。沿途收集的这 6 段就是两个列表的全部交集。
三个高频追问:为何不回退、端点相接算不算、空列表边界。
参考代码
def intervalIntersection(A, B): res = [] i = j = 0 while i < len(A) and j < len(B): lo = max(A[i][0], B[j][0]) # 起点取大 hi = min(A[i][1], B[j][1]) # 终点取小 if lo <= hi: # 有重叠 res.append([lo, hi]) if A[i][1] < B[j][1]: # 终点小者前进 i += 1 else: j += 1 return res复杂度
- 时间:O(m+n),i、j 各自只往后走,两个列表合起来共 m+n 个区间,每个最多被看一次
- 空间:O(1),除答案数组外只用 i、j 两个指针,不开额外结构(答案本身不计入)
易错点
面试追问把动画讲成自己的话
追问为什么这道题双指针都不用回退?
追问两区间只在一个端点相接(如 [5,10] 和 [1,5])算不算交集?
追问如果某个列表为空,结果是什么?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
戳气球
LeetCode 312 · 困难 · 沿着 区间套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题