Algorithm

Insert Interval

Greedy & Intervals Pattern

Insert Interval

You are given a list of non-overlapping intervals sorted in ascending order by start time, and a single new interval. Insert the new interval so that the result is still sorted and still non-overlapping, merging the new interval with any existing intervals it overlaps or touches. Return the resulting list. The input may be empty, in which case the answer is just the new interval.

CONSTRAINTS
  • 0 ≤ intervals.length ≤ 10⁴
  • Each interval and the new interval have the form [start, end] with start ≤ end
  • The existing intervals are already sorted by start and are pairwise non-overlapping
  • Intervals touching at an endpoint count as overlapping and are merged
EXAMPLE 1
Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]
The new interval [2,5] overlaps [1,3], fusing into [1,5]. The interval [6,9] starts after 5 and is untouched.
EXAMPLE 2
Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
Output: [[1,2],[3,10],[12,16]]
The new interval stretches across [3,5], [6,7] and [8,10], absorbing all three into [3,10]. The far ends [1,2] and [12,16] are unaffected.
EXAMPLE 3
Input: intervals = [], newInterval = [5,7]
Output: [[5,7]]
With no existing intervals, the new one is simply the entire result.
EXAMPLE 4
Input: intervals = [[1,5]], newInterval = [2,3]
Output: [[1,5]]
The new interval lies entirely inside the existing one, so the maximum-based growth leaves [1,5] unchanged.
EXAMPLE 5
Input: intervals = [[1,5]], newInterval = [6,8]
Output: [[1,5],[6,8]]
The new interval starts after the existing one ends, so no merge happens and it is appended after.
Is the existing list guaranteed sorted and non-overlapping?
Yes, and that is the whole point — it lets you insert in a single linear pass instead of re-sorting. If it were not sorted, this would reduce to Merge Intervals with an O(N log N) sort.
Do touching intervals merge with the new one?
Yes, touching counts as overlapping here, which is why the phase boundaries use ≤ rather than strict inequality. Confirm this convention, since it decides whether an interval ending exactly at the new start gets merged or copied.
Can the input list be empty?
Yes. With no existing intervals the answer is just the new interval on its own, which the three-phase pass handles naturally by skipping straight to appending it.
Does the new interval always end up merged with something?
Not necessarily. If it overlaps nothing, phase 2 absorbs no intervals and it is inserted as its own block between the before and after groups.
Use the gift you were given

The crucial words in the statement are "sorted" and "non-overlapping". The existing intervals already have the exact structure that Merge Intervals worked hard to build. Only one new interval disturbs the order, and it can only interfere with a contiguous run of the existing intervals — the ones its time range touches. Everything before that run is untouched, and everything after it is untouched.

That structure means you do not need to sort anything. You can walk the list once and stitch the new interval into place.

The lazy approach, and why it wastes the gift

The tempting shortcut: append the new interval and run the full Merge Intervals routine.

python
def insert_naive(intervals, new):
    return merge(intervals + [new])     # sorts from scratch: O(N log N)

It works, but it throws away the sortedness you were handed and pays O(N log N) to rebuild an order that was already there. When a problem hands you a sorted input, re-sorting is almost always a sign you have missed the intended O(N) solution.

The three phases

Because the list is sorted, the intervals fall into exactly three consecutive groups relative to the new interval, and you handle each group in one linear pass:

1. Entirely before. An existing interval that ends before the new interval starts (end < new_start) cannot touch it. Copy these straight through.
2. Overlapping. An existing interval overlaps the new one when it starts at or before the new interval's current end (start <= new_end). Absorb each such interval into the new one by growing the new interval: its start becomes the min of the two starts, its end the max of the two ends. Keep doing this as long as intervals keep overlapping — the new interval swells to swallow the whole run. Then add the swollen new interval once.
3. Entirely after. Everything remaining starts strictly after the new interval ends. Copy these through unchanged.

The key realisation is that the overlapping middle group is contiguous: once you pass an interval that starts after the new one's (possibly grown) end, no later interval can reach back, because the list is sorted by start. So a single forward walk cleanly separates the three groups.

python
def insert(intervals, new):
    res = []
    i, n = 0, len(intervals)

    # Phase 1: intervals ending before new starts — untouched.
    while i < n and intervals[i][1] < new[0]:
        res.append(intervals[i])
        i += 1

    # Phase 2: intervals overlapping new — absorb them into new.
    while i < n and intervals[i][0] <= new[1]:
        new[0] = min(new[0], intervals[i][0])
        new[1] = max(new[1], intervals[i][1])
        i += 1
    res.append(new)

    # Phase 3: intervals starting after new ends — untouched.
    while i < n:
        res.append(intervals[i])
        i += 1

    return res

One pass, O(N) time.

Crucial Notethe boundary tests decide correctness. Phase 1 uses end < new_start (strict) so that an interval merely touching the new one's start is not skipped past — it belongs in the overlap phase, since touching counts as overlapping here. Phase 2 uses start <= new_end for the same reason: an existing interval that begins exactly at the new one's end still touches it. Flip either comparison and touching intervals get mishandled. If the problem's convention were that touching does not overlap, both comparisons would tighten by one.
Worked Example:intervals = [[1,3],[6,9]], new = [2,5]
- Phase 1: [1,3] — does 3 < 2 (new start)? No. So no interval is strictly before; skip phase 1.
- Phase 2: [1,3] — does 1 ≤ 5 (new end)? Yes, overlap. Grow new to [min(2,1), max(5,3)] = [1,5]. Advance. [6,9] — does 6 ≤ 5? No. Stop. Append the grown new: result [[1,5]].
- Phase 3: [6,9] remains, starts after 5. Copy it. Result [[1,5],[6,9]].

Answer [[1,5],[6,9]].

A case where the new interval swallows several: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], new = [4,8]. Phase 1 copies [1,2] and [3,5]? No — [3,5] ends at 5 which is not < 4, so only [1,2] is strictly before. Phase 2 absorbs [3,5], [6,7], [8,10] (all start ≤ the growing end) into [3,10]. Phase 3 copies [12,16]. Result [[1,2],[3,10],[12,16]] — one new interval devoured three existing ones.

The takeaway

The lesson here is about reading the shape of your input and refusing to discard it. A sorted, non-overlapping list is a strong precondition, and the intended solution almost always exploits it to reach O(N) rather than paying O(N log N) to recreate order that was already present.

The reusable structural insight — a single new element disturbs a sorted list only within a contiguous window, so a three-phase pass (before / affected / after) handles it in linear time — appears well beyond intervals: inserting into a sorted array, applying one update to a sorted event stream, splicing a range into a timeline. Whenever exactly one thing changes in an otherwise-ordered collection, look for the contiguous affected window and walk the three regions.

This is Merge Intervals with the sort already done for you and only one troublemaker to place. If you understood the anchor-and-sweep there, this is that same sweep, aimed at a single interval.

Interactive Strategy Visualization

Three-Phase Insertion

0
2
4
6
8
10
Input & New
[1,3]
[6,9]
NEW: [2,5]
Result
Goal: Insert [2, 5] into sorted intervals [[1, 3], [6, 9]].
THE STRATEGY

Since the input is sorted, we can avoid O(N log N) re-sorting. We build the result in three clean phases: Before, Overlap, and After.

EFFICIENCY

This "one-pass" approach runs in O(N) time, where N is the number of intervals. We visit each interval exactly once.

O(N log N) Append and Re-sort
O(N) Time Three-Phase Linear Insert