A calendar application needs to schedule a new meeting from 2pm to 4pm against existing meetings from 1pm to 3pm and 3:30pm to 5pm. Does the new meeting conflict? How do you check this efficiently for hundreds of meetings?
This is an interval problem. Intervals appear everywhere in software: calendar systems, booking platforms, resource allocation, genomic data analysis, network packet scheduling, and database query optimization. Detecting overlaps, merging ranges, and finding gaps efficiently is a core skill.
Determining overlap correctly, handling edge cases, and doing it efficiently for thousands of intervals requires careful thinking. A few patterns cover most interval problems.
This chapter uses closed intervals [start, end] throughout. The overlap condition is a.start <= b.end && b.start <= a.end. For half-open [start, end) problems (common in scheduling APIs like Meeting Rooms II), replace <= with < so that meeting [1,5) does not conflict with [5,8).
An interval represents a continuous range with a start and end point. In coding problems, intervals are typically represented as arrays or objects with two values.
Intervals can be:
Most LeetCode problems use closed intervals [start, end], meaning both the start and end values are part of the interval.
The most common interval question is whether two intervals overlap.
Given interval A = [a, b] and interval B = [c, d], they overlap if and only if:
This condition checks that A starts before B ends AND B starts before A ends. It is often easier to think about the negation: two intervals do NOT overlap if:
This means either A ends before B starts, or B ends before A starts.
The "touch at endpoint" case (where one interval ends exactly where another starts) frequently causes off-by-one bugs. Whether [1,5] and [5,8] are considered overlapping depends on whether the problem uses closed or half-open intervals. Read the problem statement carefully.
Most interval algorithms begin with sorting. The two common approaches are:
Sort by start time: Used for merging intervals. After sorting, overlapping intervals become adjacent, making them easy to merge in a single pass.
Sort by end time: Used for interval selection problems (like activity selection). By always picking the interval that ends earliest, you leave maximum room for subsequent intervals. The exchange-argument proof: any optimal schedule can be transformed into the greedy one by swapping each interval with the earliest-ending compatible alternative without reducing the count.
| Sort By | Use Case | Why It Works |
|---|---|---|
| Start time | Merge overlapping intervals | Overlapping intervals become consecutive |
| End time | Select maximum non-overlapping | Earliest end leaves most room for others |
| Start time (then by end) | Insert into sorted list | Maintain sorted order for binary search |
When intervals share start or end times, secondary sort order can change correctness.
[s, e), an end event at time t should come before a start event at time t so that back-to-back meetings do not double-count. For closed intervals [s, e], the order reverses.Read the problem statement carefully for inclusive vs. exclusive endpoint semantics before writing the comparator.
When two intervals overlap, merging them creates a single interval:
The merged interval starts at whichever interval started earlier and ends at whichever ended later.
Problem: given a list of intervals, merge all overlapping intervals and return the result.
The merge step expands the last result interval's end to max(last.end, current.end). The end of the last interval can only grow, never shrink, so a single pass is enough.
Trace on [[1,3],[2,6],[8,10],[15,18]]:
[[1,3],[2,6],[8,10],[15,18]] (already sorted).result = [[1,3]] with the first interval.[2,6]: 2 <= 3 (overlap), merge by setting end to max(3, 6) = 6. result = [[1,6]].[8,10]: 8 > 6 (no overlap), append. result = [[1,6],[8,10]].[15,18]: 15 > 10 (no overlap), append. result = [[1,6],[8,10],[15,18]].Final result: [[1,6],[8,10],[15,18]].
Time Complexity: O(n log n) for the sort, O(n) for the merge pass. Total: O(n log n).
Space Complexity: O(n) for the output list. Auxiliary space is O(log n) for the sort on most implementations.
Problem: given a sorted, non-overlapping interval list and a new interval, insert the new interval and merge any resulting overlaps.
Walk through the input list in three phases:
newInterval[0] = min(newInterval[0], current[0]) and newInterval[1] = max(newInterval[1], current[1]).Because the input is already sorted, a single pass is enough. No global sort is needed, so the work is linear in the input size.
Trace on intervals = [[1,3],[6,9]], newInterval = [2,5]:
[1,3] ends at 3, and 3 is not less than newInterval[0] = 2. Stop the before phase without appending.[1,3] starts at 1, which is <= newInterval[1] = 5, so they overlap. Update newInterval = [min(2,1), max(5,3)] = [1,5]. Advance to [6,9]. 6 > 5, so the merge phase ends.newInterval = [1,5], then append [6,9].Final result: [[1,5],[6,9]].
Time Complexity: O(n) since each input interval is visited once.
Space Complexity: O(n) for the output list.
Two related problems use the same input shape but answer different questions.
Problem: given an array of meeting time intervals, determine whether a single person can attend all meetings without conflicts.
Approach: sort by start time. For each consecutive pair, return false if the previous meeting's end is greater than the current meeting's start. Half-open semantics treat [1,5] and [5,8] as non-conflicting (the room frees at end time).
This is a building block. The harder cousin asks for the minimum number of rooms.
Problem: given an array of meeting time intervals, return the minimum number of conference rooms required to host all meetings.
Approach (min-heap by end time): sort intervals by start time. Maintain a min-heap of meeting end times. For each new meeting, check whether the earliest-ending meeting on the heap has already ended (its end time is at or before the new meeting's start). If yes, pop it (that room is now free). Push the new meeting's end time. The heap size at any moment equals the number of rooms currently in use, and the maximum heap size during the iteration is the answer. Because the heap can only shrink when a room is freed and only grows when a new meeting starts, its final size is also the maximum size reached.
Trace on [[0,30],[5,10],[15,20]]:
[[0,30],[5,10],[15,20]] (already sorted).[0,30]: heap empty, push 30. Heap = [30].[5,10]: heap top is 30, and 30 > 5, so no room is free. Push 10. Heap = [10, 30].[15,20]: heap top is 10, and 10 <= 15, so that room is free. Pop 10, push 20. Heap = [20, 30].Answer: 2 rooms.
Time Complexity: O(n log n) for the sort plus O(n log n) for heap operations.
Space Complexity: O(n) for the heap in the worst case (all meetings concurrent).
Approach 2 (sweep line / chronological events): treat each meeting as two events, +1 at its start and -1 at its end. Sort the events by position, then sweep through them while tracking a running counter. The maximum value of the counter is the answer. This runs in O(n log n) with a different constant factor and shares the framework used by other interval problems (see the next section).
Sweep line is a general framework for interval problems. Convert each interval into two events (a start event and an end event), sort the events by position, and sweep through them while maintaining a running counter that tracks active intervals.
[s, e], emit two events: (s, +1) and (e, -1).-1) typically come before start events (+1) at the same position to model half-open intervals; reverse the order for closed intervals.For Meeting Rooms II, the answer is the maximum counter value reached during the sweep. The sort by (position, delta) produces the correct tie-breaking for half-open intervals because -1 < +1.
The same event-counter pattern solves several related problems:
The pattern is a useful mental tool when a problem asks "how many things are active at the busiest moment" or "what is the union/gap structure across many intervals".
Problem: given a list of intervals, return the minimum number of intervals to remove so that the remaining intervals are non-overlapping.
This is equivalent to the interval scheduling maximization problem: find the largest subset of intervals that do not overlap. The answer to the original problem is n - max_nonoverlapping.
Greedy by end time. Sort the intervals by end time. Iterate through the sorted list, greedily picking each interval whose start is greater than or equal to the last picked interval's end.
Exchange argument: any optimal schedule can be transformed into this greedy one without reducing the count, by swapping each picked interval with the earliest-ending compatible alternative. Picking the earliest-ending compatible interval leaves the most room for subsequent picks, which is why greedy-by-end is optimal here while greedy-by-start is not.
Trace on [[1,2],[2,3],[3,4],[1,3]]:
[[1,2],[2,3],[1,3],[3,4]].[1,2]. lastEnd = 2. Kept = 1.[2,3]: 2 >= 2, pick. lastEnd = 3. Kept = 2.[1,3]: 1 < 3, skip.[3,4]: 3 >= 3, pick. lastEnd = 4. Kept = 3.Removed = 4 - 3 = 1.
Time Complexity: O(n log n) for the sort, O(n) for the greedy pass.
Space Complexity: O(1) extra space beyond the input (O(log n) for the sort on most implementations).
Interval problems come in several flavors, each mapped to a sorting strategy and an approach.
| Variant | Sort By | Approach | Example Problem |
|---|---|---|---|
| Merge overlapping | Start | Extend end if overlapping with previous | Merge Intervals |
| Insert into sorted | Pre-sorted | Split into three regions: before, overlap, after | Insert Interval |
| Remove minimum overlapping | End | Greedy: pick interval that ends earliest | Non-overlapping Intervals |
| Count maximum concurrent | Events | Line sweep: +1 at start, -1 at end | Meeting Rooms II |
| Find gaps | Start | Track last end, compare with next start | Missing Ranges |
| Intersection of two lists | Two pointers | Advance pointer of interval that ends first | Interval List Intersections |
Signs that you are facing an interval problem:
When these techniques might NOT apply:
This problem uses basic overlap detection. Meeting Rooms uses half-open semantics: meeting [1,5] does not conflict with [5,8] because the rooms are released at the end time. The code below uses strict < to match this convention.
Problem: Given an array of meeting time intervals where intervals[i] = [start, end], determine if a person can attend all meetings.
If any two meetings overlap, return false. The brute force approach checks all pairs in O(n^2). But if we sort by start time, overlapping meetings become adjacent. We only need to check each meeting against the previous one.
After sorting by start time, meeting A overlaps with meeting B (where A comes before B) if and only if A's end time is greater than B's start time.
Time Complexity: O(n log n) for sorting, O(n) for the scan. Total: O(n log n).
Space Complexity: O(1) extra space (O(log n) for sorting in some implementations).
This problem uses the two-pointer approach on two sorted interval lists.
Problem: Given two lists of closed intervals, each list is pairwise disjoint (no overlaps within a list) and sorted. Return the intersection of these two interval lists.
Use two pointers, one for each list. At each step:
The intersection of [a,b] and [c,d] (when they overlap) is:
Time Complexity: O(m + n) where m and n are the lengths of the two lists.
Space Complexity: O(m + n) for the output. O(1) auxiliary space if the output array is not counted as extra space.
Many interval algorithms require sorted input. Forgetting to sort leads to incorrect results.
Sorting by start time and end time are not interchangeable.
The difference between < and <= matters for whether touching intervals count as overlapping.
Read the problem carefully to determine the expected behavior.
When building a result list incrementally, the last interval is often added inside the loop only under certain conditions. Make sure to add it after the loop.
Some problems pass the input by reference and expect the original array to remain unchanged after the function returns. This matters when the same input is reused across multiple test calls or when other code holds references to it. Creating a copy before sorting avoids this issue.
10 quizzes