Interval List Intersections
Table of Contents + β
Interval List Intersections is a favorite because both lists are already sorted. The interviewer wants to see if you can use that order. A beginner compares every pair. A strong candidate walks two pointers through the lists at the same time. That second habit is the real skill being tested.
π― The Problem
You get two sorted lists of intervals, and you must find where they overlap. Here are the rules.
- An interval is a small range, like
[1, 5], which covers every point from1to5. - Both lists are sorted by start time.
- The intervals inside each list never overlap each other.
- Return a new list of the intersections, the shared part of two intervals.
An intersection is the piece both intervals cover.
Let us look at an example. The first list is [[0,2],[5,10],[13,23],[24,25]]. The second list is [[1,5],[8,12],[15,24],[25,26]]. The shared pieces form the answer below.
Input: A = [[0,2],[5,10],[13,23],[24,25]] B = [[1,5],[8,12],[15,24],[25,26]]Output: [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]
Explanation: each output interval is the part both A and B cover.Two intervals overlap when one starts before the other ends. The shared part starts at the larger of the two starts and ends at the smaller of the two ends. If that start is past that end, there is no overlap.
Here is the shape of the problem on a number line. See where A and B cover the same points.
π’ Approach 1: Check Every Pair (Brute Force)
The idea in one line: compare each interval in the first list against each one in the second.
The idea:
- Take every interval from the first list.
- Compare it against every interval in the second list.
- For each pair, check the overlap. If real, record the shared part.
How it works:
- It ignores the sorting and just tries all pairs.
- It does give the right answer.
Why it is weak:
- You compare pairs that can never overlap, like an early interval against a late one.
- With two long lists the pair count grows fast. The time is O(n Γ m).
- It throws away the gift that both lists are sorted.
Here is the check-every-pair code:
def interval_intersection(first_list, second_list): answer = [] for a_start, a_end in first_list: for b_start, b_end in second_list: start = max(a_start, b_start) end = min(a_end, b_end) if start <= end: answer.append([start, end]) return sorted(answer)β‘ Approach 2: Two Pointers (Best)
The idea in one line: walk both sorted lists together with one pointer each.
What pointers give us:
- A pointer is an index saying which interval we look at right now in each list.
- Both lists are sorted by start, so the two pointers always move forward.
How one step works:
- Start one pointer at the first interval of each list.
- Find the overlap. It starts at the larger of the two starts and ends at the smaller of the two ends.
- If the start is not past the end, the overlap is real. Add it to the answer.
The clever move:
- Advance only the pointer whose interval ends first.
- That interval is finished. It cannot overlap anything later in the other list.
- The interval that ends later might still overlap the next one. So keep it.
Why it is fast:
- Each step moves at least one pointer forward.
- So each interval is touched once. The time is O(n + m).
Here is a dry run of the two pointers on the first few intervals. Watch which pointer moves.
Steps to Solve
- Start a pointer at the first interval of each list.
- While both pointers are still inside their lists, look at the two current intervals.
- Find the overlap start, which is the larger of the two starts.
- Find the overlap end, which is the smaller of the two ends.
- If the overlap start is not past the overlap end, add that shared interval to the answer.
- Advance the pointer whose interval has the smaller end, because that interval is finished.
- Stop when either pointer reaches the end of its list.
This Python version keeps two index pointers and builds a list of overlaps.
def interval_intersection(A, B): result = [] i, j = 0, 0 # one pointer per list
while i < len(A) and j < len(B): lo = max(A[i][0], B[j][0]) # larger of the two starts hi = min(A[i][1], B[j][1]) # smaller of the two ends if lo <= hi: # a real overlap exists result.append([lo, hi]) if A[i][1] < B[j][1]: # A ends first i += 1 # so move pointer i else: # B ends first or ties j += 1 # so move pointer j
return result
A = [[0, 2], [5, 10], [13, 23], [24, 25]]B = [[1, 5], [8, 12], [15, 24], [25, 26]]print(interval_intersection(A, B))The output of the above code will be:
[[1, 2], [5, 5], [8, 10], [15, 23], [24, 24], [25, 25]]Let us read the Python version line by line, because the two-pointer dance is the heart of it.
We begin with result = [] to hold the overlaps. Then i, j = 0, 0 puts one pointer at the start of each list. Pointer i walks list A and pointer j walks list B.
The loop runs while i < len(A) and j < len(B). We keep going only while both pointers are still inside their lists. The moment one list is done, no more overlaps can happen.
Inside, lo = max(A[i][0], B[j][0]) finds the start of the overlap. The shared part cannot begin before either interval begins. So it begins at the later start. Then hi = min(A[i][1], B[j][1]) finds the end of the overlap. The shared part must end when the first interval ends. So it ends at the earlier end.
Next if lo <= hi. This is the overlap test. If lo is not past hi, there is a real shared piece, so we append [lo, hi] to the result. If lo is greater than hi, the intervals do not touch and we add nothing.
Then the pointer move. if A[i][1] < B[j][1]: i += 1. The interval in A ends first. It is finished and cannot overlap anything later in B. So we advance i. Otherwise we advance j. We always drop the interval that ends earlier. That is what keeps each interval touched only once and makes the whole thing fast.
β±οΈ Time and Space Complexity
The brute force compares every pair, so its time grows as the two lists multiply. The two-pointer version moves at least one pointer forward each step. So it touches each interval once. That gives O(n + m) time, where n and m are the two list lengths. The only extra space is the output list itself.
| Approach | Time Complexity | Space Complexity |
|---|---|---|
| Brute force (check every pair) | O(n Γ m) | O(1) extra |
| Two pointers over sorted lists | O(n + m) | O(1) extra |
Tip
The one move to remember is which pointer to advance. Always advance the interval that ends first. It is done, so let it go and bring in the next one.
π§© Key Takeaways
- β The overlap of two intervals starts at the larger start and ends at the smaller end.
- β If that start is past that end, the intervals do not overlap at all.
- β Because both lists are sorted, two pointers can walk them together instead of checking every pair.
- β Always advance the pointer whose interval ends first, because it cannot overlap anything later.
- β Each interval is touched once, so the total time is O(n + m).
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
How do you compute the overlap of two intervals?
Why: The shared part begins at the later start and finishes at the earlier end.
- 2
When do two intervals fail to overlap?
Why: If the computed overlap start is greater than the overlap end, there is no shared piece.
- 3
Which pointer do we advance at each step?
Why: The interval that ends first is finished and cannot overlap anything later, so we move past it.
- 4
What is the time complexity of the two-pointer solution?
Why: Each step moves at least one pointer forward, so we touch each interval once across both lists.