Problem Walkthrough

Interval Intersections LeetCode 986 Guide

LeetCode 986 Interval List Intersections uses a two-pointer technique on two sorted, disjoint interval lists to find all overlapping segments in O(m+n) time — each step computes the intersection of the current pair and advances the pointer whose interval ends first.

8 min read|

Interval Intersections

LeetCode 986

Problem Overview

LeetCode 986, Interval List Intersections, gives you two sorted lists of disjoint, closed intervals — firstList and secondList — and asks you to return the intersection of these two lists. An interval [a, b] intersects [c, d] if and only if they share at least one point; the intersection is [max(a,c), min(b,d)] whenever that start does not exceed that end.

Both input lists are already sorted in ascending order and each list contains only disjoint intervals (no two intervals within the same list overlap). This structure is what makes a two-pointer approach natural: you never need to backtrack, and you can process both lists in a single left-to-right pass.

The problem is classified as Medium and is a direct member of the interval two-pointer family alongside Merge Intervals and Meeting Rooms. Understanding the overlap condition and the pointer-advance rule is the entire solution — once you see those two ideas clearly, the code is only about ten lines.

  • Input: firstList and secondList, each a sorted list of disjoint closed intervals
  • Each interval is [start, end] with start <= end (inclusive on both ends)
  • Constraints: 0 <= firstList.length, secondList.length <= 1000
  • Interval values: 0 <= start_i < end_i <= 10^9
  • Return the intersection of the two interval lists as a list of intervals
  • If either list is empty, the intersection is empty — return []

Two-Pointer Approach

Use pointer i for firstList and pointer j for secondList, both starting at 0. At each step, you consider the current pair A[i] and B[j]. Compute whether they overlap, and if so record the intersection. Then advance the pointer whose interval ends first — that interval cannot contribute any further overlaps because the other pointer has not yet passed its end.

The key insight is that because both lists are sorted and disjoint, the interval that ends sooner among A[i] and B[j] can never overlap with any future interval from its own list (since future intervals start later than its end). The interval that ends later, however, might still overlap with the next interval from the other list — so we keep it in place and only advance the shorter one.

This greedy pointer-advance rule is the heart of the algorithm. It guarantees that every pair of intervals is considered at most once, giving O(m+n) total iterations where m = len(firstList) and n = len(secondList). The loop terminates when either pointer exhausts its list.

💡

Two Intervals Overlap if max(startA, startB) <= min(endA, endB)

Two intervals overlap if and only if max(startA, startB) <= min(endA, endB). This single condition replaces checking multiple overlap cases such as "does A start before B ends and B starts before A ends." When the condition holds, the intersection is exactly [max(startA, startB), min(endA, endB)]. Memorize this formula — it applies to every interval overlap problem.

Computing Each Intersection

For the current pair A[i] = [startA, endA] and B[j] = [startB, endB], the potential intersection starts at intersectionStart = max(startA, startB) and ends at intersectionEnd = min(endA, endB). If intersectionStart <= intersectionEnd, the intervals actually overlap and [intersectionStart, intersectionEnd] is a valid intersection interval to add to the result.

If intersectionStart > intersectionEnd, the intervals do not overlap — one ends before the other begins — and you produce no output for this pair. You still advance the pointer whose interval ends sooner and continue to the next pair.

Because the input intervals are closed (both endpoints are included), a single shared point counts as an intersection. For example [1, 2] and [2, 3] intersect at [2, 2]. The condition max(start) <= min(end) correctly captures this: 2 <= 2 is true, and the intersection [2, 2] is valid.

  1. 1Let [startA, endA] = firstList[i] and [startB, endB] = secondList[j]
  2. 2Compute intersectionStart = max(startA, startB)
  3. 3Compute intersectionEnd = min(endA, endB)
  4. 4If intersectionStart <= intersectionEnd, append [intersectionStart, intersectionEnd] to result
  5. 5Advance the pointer with the smaller end value (see next section)
  6. 6Repeat until i >= len(firstList) or j >= len(secondList)

Advancing the Right Pointer

After processing the current pair, advance the pointer whose interval ends first. If endA < endB, increment i (move to the next interval in firstList). Otherwise increment j (move to the next interval in secondList). When endA == endB, it does not matter which you advance — both intervals end at the same point so neither can overlap with anything the other has not yet seen.

This rule is correct because an interval that ends before the other cannot overlap with any future interval from the other list — those future intervals start at or after the current interval in the other list ends, which is already past the end of the interval we are discarding. The interval that ends later, however, might reach into the next interval from the other list.

A common mistake is to advance both pointers when the current pair overlaps. Do not do this. Only advance the pointer whose interval ends sooner. The longer interval may still overlap with one or more subsequent intervals from the other list, and advancing both would skip those intersections.

ℹ️

Advancing the Shorter Interval Is Always Safe

Advancing the interval that ends first is correct because it cannot overlap with anything else from the other list — all remaining intervals in the other list start at or after the current other-list interval, and the current shorter interval already ended before that. The longer interval might still reach into subsequent intervals from the other list, so keep its pointer in place.

Walk-Through Example

Consider A = [[0,2],[5,10],[13,23],[24,25]] and B = [[1,5],[8,12],[15,24],[25,26]]. Start with i=0, j=0. A[0]=[0,2] and B[0]=[1,5]: intersection = [max(0,1), min(2,5)] = [1,2]. Since endA=2 < endB=5, advance i to 1.

Now i=1, j=0. A[1]=[5,10] and B[0]=[1,5]: intersection = [max(5,1), min(10,5)] = [5,5]. Since endA=10 > endB=5, advance j to 1. Now i=1, j=1. A[1]=[5,10] and B[1]=[8,12]: intersection = [8,10]. Since endA=10 < endB=12, advance i to 2.

Continue: i=2, j=1. A[2]=[13,23] vs B[1]=[8,12]: max(13,8)=13, min(23,12)=12 — no overlap (13 > 12), advance j (endB=12 < endA=23) to 2. i=2, j=2: A[2]=[13,23] vs B[2]=[15,24]: intersection = [15,23], advance i. i=3, j=2: A[3]=[24,25] vs B[2]=[15,24]: intersection = [24,24], advance j. i=3, j=3: A[3]=[24,25] vs B[3]=[25,26]: intersection = [25,25]. Result: [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]].

  1. 1i=0,j=0: A=[0,2] B=[1,5] → [1,2] (endA<endB → i++)
  2. 2i=1,j=0: A=[5,10] B=[1,5] → [5,5] (endA>endB → j++)
  3. 3i=1,j=1: A=[5,10] B=[8,12] → [8,10] (endA<endB → i++)
  4. 4i=2,j=1: A=[13,23] B=[8,12] → no overlap 13>12 (endB<endA → j++)
  5. 5i=2,j=2: A=[13,23] B=[15,24] → [15,23] (endA<endB → i++)
  6. 6i=3,j=2: A=[24,25] B=[15,24] → [24,24] (endB<endA → j++)
  7. 7i=3,j=3: A=[24,25] B=[25,26] → [25,25] — done

Code Walkthrough — Python and Java

Python: def intervalIntersection(A, B): i = j = 0; result = []; 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: result.append([lo, hi]); if A[i][1] < B[j][1]: i += 1; else: j += 1; return result. Time complexity O(m+n), space O(1) extra (the result list does not count as extra space).

Java: List<int[]> res = 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) res.add(new int[]{lo, hi}); if (A[i][1] < B[j][1]) i++; else j++; } return res.toArray(new int[0][]). Both implementations are compact and run in O(m+n) time with O(1) auxiliary space.

The while loop terminates as soon as either pointer reaches the end of its list, because no further intersections can exist once one list is exhausted. The result list can contain at most m+n intervals in the worst case (when every interval in one list overlaps with exactly one interval in the other), so output space is O(m+n) but this is not counted as "extra" space since it is the required output.

⚠️

Don't Confuse Intersection with Merge Intervals

Don't confuse this problem with Merge Intervals (LeetCode 56). In Merge Intervals, a single unsorted list may have overlapping intervals that you combine into one. In Interval List Intersections, both lists are already sorted and disjoint — you are finding where intervals from different lists overlap each other, not combining intervals within the same list. The two-pointer approach here relies on the already-sorted, already-disjoint structure of the input.

Ready to master algorithm patterns?

YeetCode flashcards help you build pattern recognition through active recall and spaced repetition.

Start practicing now