Loading problems...
TL;DR: The optimal solution uses a two-pointer greedy approach to iterate through both sorted lists simultaneously, calculating overlaps using max(start) and min(end) and advancing the pointer of the interval that ends earlier.
This problem asks us to compute the intersection of two lists of closed intervals. We are given firstList and secondList, where each list consists of pairwise disjoint (non-overlapping) intervals sorted by their start times. Our goal is to return a new list of intervals representing the ranges covered by both input lists simultaneously.
The LeetCode 986 problem, "Interval List Intersections," is a standard interview question that tests your ability to manipulate array indices and handle interval logic efficiently without resorting to quadratic comparisons.
A naive approach to solving the Interval List Intersections problem involves ignoring the sorted nature of the input lists and comparing every interval in the first list with every interval in the second list.
A in .firstListB in secondList.A and B overlap.
max(A.start, B.start) <= min(A.end, B.end).[max(A.start, B.start), min(A.end, B.end)] to the results.Time Complexity: , where and are the lengths of the two lists. Space Complexity: auxiliary space (excluding output).
Why it fails: While the constraints () might allow this solution to pass without a Time Limit Exceeded (TLE) error on some platforms, it is fundamentally inefficient. It performs redundant comparisons and fails to utilize the critical property that the input lists are sorted and disjoint. In a serious interview context, an solution for sorted inputs is considered suboptimal.
The key to solving LeetCode 986 efficiently lies in the "Two Pointers" technique applied within a greedy framework. Since both lists are sorted by start time, we can iterate through them in a single pass.
The core logic revolves around how we determine the intersection and how we advance our pointers:
A and B intersect if the start of the intersection window is less than or equal to the end of the intersection window. Mathematically, the intersection is [max(A.start, B.start), min(A.end, B.end)]. If max_start <= min_end, we have a valid intersection.firstList[i] and secondList[j], we must decide which pointer to advance (i or j).
firstList[i] ends before secondList[j], it is impossible for firstList[i] to intersect with any subsequent intervals in secondList (because secondList is sorted). Therefore, we are finished with firstList[i] and should increment i.secondList[j] ends before firstList[i], we increment j.Visual Description: Imagine two horizontal timelines. We place a pointer at the beginning of each list. We look at the two current intervals. We mathematically determine the "overlap zone" based on the latest start time and the earliest end time. Once we record any overlap, we look at the endpoints. The interval that finishes earliest is "discarded" because its timeline has been fully processed relative to the current position of the other list. We move that pointer forward to bring the next interval into consideration.

Let's trace firstList = [[0,2], [5,10]] and secondList = [[1,5], [8,12]].
Step 1: i=0 ([0,2]), j=0 ([1,5]).
lo = max(0, 1) = 1.hi = min(2, 5) = 2.lo <= hi is true. Add [1, 2] to result.firstList[0].end (2) < secondList[0].end (5). Increment i.Step 2: i=1 ([5,10]), j=0 ([1,5]).
lo = max(5, 1) = 5.hi = min(10, 5) = 5.lo <= hi is true. Add [5, 5] to result.secondList[0].end (5) < firstList[1].end (10). Increment j.Step 3: i=1 ([5,10]), j=1 ([8,12]).
lo = max(5, 8) = 8.hi = min(10, 12) = 10.lo <= hi is true. Add [8, 10] to result.firstList[1].end (10) < secondList[1].end (12). Increment i.Step 4: i is now 2, which equals firstList.length. Loop terminates.
The correctness relies on the sorted and disjoint properties. When we compare interval and interval , and we find that , we claim we can safely discard . Why?
Because the other list is sorted, any subsequent interval will have . Since , it implies . Thus, cannot possibly overlap with or any interval after it. This guarantees that by moving the pointer of the interval ending first, we never miss a future intersection.
cppclass Solution { public: vector<vector<int>> intervalIntersection(vector<vector<int>>& firstList, vector<vector<int>>& secondList) { vector<vector<int>> result; int i = 0; // Pointer for firstList int j = 0; // Pointer for secondList while (i < firstList.size() && j < secondList.size()) { // Let's check if firstList[i] intersects secondList[j]. // lo - the start of the intersection // hi - the end of the intersection int lo = max(firstList[i][0], secondList[j][0]); int hi = min(firstList[i][1], secondList[j][1]); // If lo <= hi, we have a valid intersection if (lo <= hi) { result.push_back({lo, hi}); } // Remove the interval with the smallest endpoint if (firstList[i][1] < secondList[j][1]) { i++; } else { j++; } } return result; } };
javaclass Solution { public int[][] intervalIntersection(int[][] firstList, int[][] secondList) { List<int[]> resultList = new ArrayList<>(); int i = 0; int j = 0; while (i < firstList.length && j < secondList.length) { // Find the intersection boundaries int lo = Math.max(firstList[i][0], secondList[j][0]); int hi = Math.min(firstList[i][1], secondList[j][1]); // If valid intersection, add to list if (lo <= hi) { resultList.add(new int[]{lo, hi}); } // Advance the pointer of the interval that ends first if (firstList[i][1] < secondList[j][1]) { i++; } else { j++; } } return resultList.toArray(new int[resultList.size()][]); } }
pythonclass Solution: def intervalIntersection(self, firstList: List[List[int]], secondList: List[List[int]]) -> List[List[int]]: result = [] i, j = 0, 0 while i < len(firstList) and j < len(secondList): # Let's check if firstList[i] intersects secondList[j]. # lo - the start of the intersection # hi - the end of the intersection lo = max(firstList[i][0], secondList[j][0]) hi = min(firstList[i][1], secondList[j][1]) # If lo <= hi, we have a valid intersection if lo <= hi: result.append([lo, hi]) # Remove the interval with the smallest endpoint if firstList[i][1] < secondList[j][1]: i += 1 else: j += 1 return result
Time Complexity: We perform a single pass through both lists. In each iteration, we increment exactly one pointer. The total number of iterations is at most , where and are the lengths of the input lists.
Space Complexity: or The algorithm uses constant extra space for pointers and temporary variables. If we consider the output list as part of the complexity, it is in the worst case (e.g., identical lists). For complexity analysis excluding the output, it is .
The greedy interval pattern used in LeetCode 986 is highly transferable. Understanding how to sort (if necessary) and sweep through intervals allows you to solve:
Mastering the "sort and sweep" or "two-pointer scan" on intervals is essential for these popular interview questions.
Why did I get a Time Limit Exceeded (TLE) even with the correct logic?
sort() adds unnecessary complexity.Why is my output missing single-point intersections (e.g., )?
[5,5]if (lo < hi) instead of if (lo <= hi).Why am I getting Index Out of Bounds errors?
i < len and j < len incorrectly in the loop condition.Why is my logic failing on disjoint intervals?
if statements (e.g., if startA < endB and startB < endA...) instead of the max(starts) and min(ends) formula.lo = max(start1, start2) and hi = min(end1, end2) handles all cases, including non-overlapping ones (where lo > hi).