Medium
题目描述
给定两个由一些闭区间组成的列表,firstList 和 secondList,其中 firstList[i] = [starti, endi] 而 secondList[j] = [startj, endj]。每个区间列表都是成对不相交的,并且已经排序。
返回这两个区间列表的交集。
形式上,闭区间 [a, b](其中 a <= b)表示实数 x 的集合,而 a <= x <= b。
两个闭区间的交集是一组实数,要么为空集,要么为闭区间。例如,[1, 3] 和 [2, 4] 的交集为 [2, 3]。
示例 1:
输入:firstList = [[0,2],[5,10],[13,23],[24,25]], secondList = [[1,5],[8,12],[15,24],[25,26]]
输出:[[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]
示例 2:
输入:firstList = [[1,3],[5,9]], secondList = []
输出:[]
提示:
0 <= firstList.length, secondList.length <= 1000firstList.length + secondList.length >= 10 <= starti < endi <= 10^9endi < starti+10 <= startj < endj <= 10^9endj < startj+1
解题思路
这道题是经典的双指针问题,利用两个列表都已排序的特性来求交集。
核心思路: 使用两个指针分别遍历两个区间列表,对于当前比较的两个区间,判断是否有交集:
- 两个区间
[a, b]和[c, d]有交集的条件是:max(a, c) <= min(b, d) - 如果有交集,交集区间为
[max(a, c), min(b, d)]
移动指针的策略: 比较两个当前区间的结束时间,结束时间较早的区间指针向前移动。这是因为结束较早的区间不可能再与后续区间产生交集。
算法步骤:
- 初始化两个指针
i和j分别指向两个列表的开头 - 当两个指针都在有效范围内时:
- 计算当前两个区间的交集
- 如果交集存在,加入结果列表
- 移动结束时间较早的区间对应的指针
- 返回结果列表
时间复杂度为 O(m + n),空间复杂度为 O(1)(不考虑输出空间)。
代码实现
class Solution {
public:
vector<vector<int>> intervalIntersection(vector<vector<int>>& firstList, vector<vector<int>>& secondList) {
vector<vector<int>> result;
int i = 0, j = 0;
while (i < firstList.size() && j < secondList.size()) {
int start = max(firstList[i][0], secondList[j][0]);
int end = min(firstList[i][1], secondList[j][1]);
if (start <= end) {
result.push_back({start, end});
}
if (firstList[i][1] < secondList[j][1]) {
i++;
} else {
j++;
}
}
return result;
}
};
class Solution:
def intervalIntersection(self, firstList: List[List[int]], secondList: List[List[int]]) -> List[List[int]]:
result = []
i = j = 0
while i < len(firstList) and j < len(secondList):
start = max(firstList[i][0], secondList[j][0])
end = min(firstList[i][1], secondList[j][1])
if start <= end:
result.append([start, end])
if firstList[i][1] < secondList[j][1]:
i += 1
else:
j += 1
return result
public class Solution {
public int[][] IntervalIntersection(int[][] firstList, int[][] secondList) {
var result = new List<int[]>();
int i = 0, j = 0;
while (i < firstList.Length && j < secondList.Length) {
int start = Math.Max(firstList[i][0], secondList[j][0]);
int end = Math.Min(firstList[i][1], secondList[j][1]);
if (start <= end) {
result.Add(new int[] {start, end});
}
if (firstList[i][1] < secondList[j][1]) {
i++;
} else {
j++;
}
}
return result.ToArray();
}
}
var intervalIntersection = function(firstList, secondList) {
const result = [];
let i = 0, j = 0;
while (i < firstList.length && j < secondList.length) {
const start = Math.max(firstList[i][0], secondList[j][0]);
const end = Math.min(firstList[i][1], secondList[j][1]);
if (start <= end) {
result.push([start, end]);
}
if (firstList[i][1] < secondList[j][1]) {
i++;
} else {
j++;
}
}
return result;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(m + n) | m 和 n 分别为两个列表的长度,每个区间最多被访问一次 |
| 空间复杂度 | O(1) | 只使用常数额外空间(不考虑输出数组的空间) |
相关题目
. Merge Intervals (Medium)
. Merge Sorted Array (Easy)
. Employee Free Time (Hard)