今天我想和大家分享一个经典的算法问题——区间列表的交集计算。这个问题在LeetCode上编号为986,难度为中等(4级)。作为一名经常处理区间类问题的开发者,我发现这个问题很好地考察了对双指针技巧的掌握程度,也让我对区间操作有了更深的理解。
区间交集问题在实际开发中有很多应用场景,比如会议室预定系统需要检查时间段的冲突,日历应用需要显示多个用户的共同空闲时间,或者数据库查询优化中需要合并多个条件范围。理解这个问题的解法,能帮助我们更好地处理这类需求。
给定两个由闭区间组成的列表firstList和secondList,其中:
这两个列表中的区间已经按照起始点排序,且同一个列表内的区间互不重叠。我们的任务是找出这两个列表的所有交集区间。
让我们看一个具体例子来理解问题:
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]]
为什么是这样呢?让我们分解来看:
在实际编码时,我们需要考虑一些特殊情况:
由于两个列表都已经排序且内部不重叠,我们可以使用双指针技术高效地找出所有交集。基本思路是:
让我们详细看看如何计算两个区间[a1, a2]和[b1, b2]的交集:
移动指针的策略也很重要:
java复制class Solution {
public int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
List<int[]> result = new ArrayList<>();
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 if (firstList[i][1] > secondList[j][1]) {
j++;
} else {
i++;
j++;
}
}
return result.toArray(new int[result.size()][]);
}
}
时间复杂度:O(m+n),其中m和n分别是两个列表的长度。我们最多只需要遍历每个列表一次。
空间复杂度:O(m+n),用于存储结果。最坏情况下,每个区间都有交集。
好的测试用例应该包括:
虽然双指针解法已经很高效,但在某些情况下还可以优化:
这个算法在实际中有很多应用:
在处理这类区间问题时,我有几点心得:
这个问题的关键在于理解如何高效地找出所有可能的交集,而双指针方法完美地利用了区间已排序的特性。在实际面试中,这类问题也很常见,因为它能很好地考察候选人对基本算法的理解和应用能力。