Medium

题目描述

给定两个由一些闭区间组成的列表,firstListsecondList,其中 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 <= 1000
  • firstList.length + secondList.length >= 1
  • 0 <= starti < endi <= 10^9
  • endi < starti+1
  • 0 <= startj < endj <= 10^9
  • endj < startj+1

解题思路

这道题是经典的双指针问题,利用两个列表都已排序的特性来求交集。

核心思路: 使用两个指针分别遍历两个区间列表,对于当前比较的两个区间,判断是否有交集:

  • 两个区间 [a, b][c, d] 有交集的条件是:max(a, c) <= min(b, d)
  • 如果有交集,交集区间为 [max(a, c), min(b, d)]

移动指针的策略: 比较两个当前区间的结束时间,结束时间较早的区间指针向前移动。这是因为结束较早的区间不可能再与后续区间产生交集。

算法步骤:

  1. 初始化两个指针 ij 分别指向两个列表的开头
  2. 当两个指针都在有效范围内时:
    • 计算当前两个区间的交集
    • 如果交集存在,加入结果列表
    • 移动结束时间较早的区间对应的指针
  3. 返回结果列表

时间复杂度为 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)只使用常数额外空间(不考虑输出数组的空间)

相关题目