Interval List Intersections
Intersect two lists of disjoint sorted intervals — merge-walk with two pointers.
3 min read
intervals two-pointers
Problem#
Given two lists of pairwise-disjoint, sorted-by-start intervals, return their intersection.
Examples#
A = [[0,2],[5,10]], B = [[1,5],[8,12]]→[[1,2],[5,5],[8,10]]
Constraints#
0 <= A.length, B.length <= 1000.
Approach#
Two-pointer merge walk. The intersection of A[i] and B[j] is [max(a0,b0), min(a1,b1)] if non-empty. Advance the pointer with the smaller end.
Solution#
class Solution {public: vector<vector<int>> intervalIntersection(vector<vector<int>>& A, vector<vector<int>>& B) { vector<vector<int>> ans; int i = 0, j = 0; while (i < (int)A.size() && j < (int)B.size()) { int lo = max(A[i][0], B[j][0]); int hi = min(A[i][1], B[j][1]); if (lo <= hi) ans.push_back({lo, hi}); if (A[i][1] < B[j][1]) ++i; else ++j; } return ans; }};func intervalIntersection(A [][]int, B [][]int) [][]int { ans := [][]int{} i, j := 0, 0 for i < len(A) && j < len(B) { lo := A[i][0] if B[j][0] > lo { lo = B[j][0] } hi := A[i][1] if B[j][1] < hi { hi = B[j][1] } if lo <= hi { ans = append(ans, []int{lo, hi}) } if A[i][1] < B[j][1] { i++ } else { j++ } } return ans}from typing import List
class Solution: def intervalIntersection(self, A: List[List[int]], B: List[List[int]]) -> List[List[int]]: ans: List[List[int]] = [] i, j = 0, 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: ans.append([lo, hi]) if A[i][1] < B[j][1]: i += 1 else: j += 1 return ansfunction intervalIntersection(A, B) { const ans = []; let i = 0, j = 0; while (i < A.length && j < B.length) { const lo = Math.max(A[i][0], B[j][0]); const hi = Math.min(A[i][1], B[j][1]); if (lo <= hi) ans.push([lo, hi]); if (A[i][1] < B[j][1]) i++; else j++; } return ans;}class Solution { public int[][] intervalIntersection(int[][] A, int[][] B) { List<int[]> ans = new ArrayList<>(); int i = 0, j = 0; while (i < A.length && j < B.length) { int lo = Math.max(A[i][0], B[j][0]); int hi = Math.min(A[i][1], B[j][1]); if (lo <= hi) ans.add(new int[]{lo, hi}); if (A[i][1] < B[j][1]) i++; else j++; } return ans.toArray(new int[0][]); }}function intervalIntersection(A: number[][], B: number[][]): number[][] { const ans: number[][] = []; let i = 0, j = 0; while (i < A.length && j < B.length) { const lo = Math.max(A[i][0], B[j][0]); const hi = Math.min(A[i][1], B[j][1]); if (lo <= hi) ans.push([lo, hi]); if (A[i][1] < B[j][1]) i++; else j++; } return ans;}Editorial#
Advancing the pointer with the smaller endpoint is the right rule because anything to the right of the other endpoint can still intersect with a later interval on this side. Each pointer advances at most n + m times → linear.
Complexity#
- Time: O(n + m).
- Space: O(n + m).
Concept revision#
Related#