Before attempting this problem, you should be comfortable with:
The simplest way to find intersections is to check every interval in the first list against every interval in the second list. Two intervals overlap when one starts before the other ends and vice versa. If they do overlap, the intersection spans from the later start point to the earlier end point. This approach is straightforward but involves redundant comparisons since we ignore the fact that both lists are already sorted.
[startA, endA] in the first list:[startB, endB] in the second list:[max(startA, startB), min(endA, endB)] and add it to the result.class Solution:
def intervalIntersection(self, firstList: List[List[int]], secondList: List[List[int]]) -> List[List[int]]:
res = []
for i in range(len(firstList)):
startA, endA = firstList[i][0], firstList[i][1]
for j in range(len(secondList)):
startB, endB = secondList[j][0], secondList[j][1]
if (startA <= startB <= endA) or (startB <= startA <= endB):
res.append([max(startA, startB), min(endA, endB)])
return resWhere and are the sizes of the arrays and , respectively.
Line sweep treats intervals as events on a number line. At each interval's start, we increment an "active" counter; at each interval's end plus one, we decrement it. When the active count equals 2, it means both an interval from the first list and one from the second list are covering that point simultaneously. By processing all events in sorted order, we can identify exactly where overlaps occur without directly comparing pairs of intervals.
[start, end]:+1 at position start.-1 at position end + 1.active counter:active == 2, record the intersection from the previous position to the current position minus one.active by adding the event's value.class Solution:
def intervalIntersection(self, firstList: List[List[int]], secondList: List[List[int]]) -> List[List[int]]:
mp = defaultdict(int)
for s, e in firstList:
mp[s] += 1
mp[e + 1] -= 1
for s, e in secondList:
mp[s] += 1
mp[e + 1] -= 1
res = []
active = 0
prev = None
for x in sorted(mp):
if active == 2:
res.append([prev, x - 1])
active += mp[x]
prev = x
return resWhere and are the sizes of the arrays and , respectively.
Since both interval lists are sorted and disjoint within themselves, we can use two pointers to efficiently find intersections. At each step, we compare the current interval from each list. If they overlap, we record the intersection. Then we advance the pointer for whichever interval ends first, since that interval cannot intersect with any future intervals from the other list. This eliminates unnecessary comparisons and processes each interval exactly once.
i and j to 0, and an empty result list.[startA, endA] from firstList[i] and [startB, endB] from secondList[j].start = max(startA, startB) and end = min(endA, endB).start <= end, add [start, end] to the result.endA < endB, increment i; otherwise, increment j).class Solution:
def intervalIntersection(self, firstList: List[List[int]], secondList: List[List[int]]) -> List[List[int]]:
res = []
i = j = 0
while i < len(firstList) and j < len(secondList):
startA, endA = firstList[i]
startB, endB = secondList[j]
start = max(startA, startB)
end = min(endA, endB)
if start <= end:
res.append([start, end])
if endA < endB:
i += 1
else:
j += 1
return resWhere and are the sizes of the arrays and , respectively.
A common mistake is using an incorrect condition to check if two intervals overlap. The correct condition is start <= end where start = max(startA, startB) and end = min(endA, endB). Some developers mistakenly check if one interval's start is between the other's boundaries, which can miss edge cases like when intervals touch at a single point (e.g., [1,3] and [3,5] should produce [3,3]).
When using the two-pointer approach, advancing the wrong pointer leads to missed intersections. The key insight is to advance the pointer for the interval that ends first because that interval cannot intersect with any future intervals from the other list. Advancing based on start times or advancing both pointers simultaneously will produce incorrect results.
Failing to handle cases where one or both input lists are empty can cause index out-of-bounds errors or incorrect behavior. Always ensure your solution gracefully returns an empty result when either firstList or secondList is empty, which the two-pointer approach handles naturally by never entering the while loop.