// pattern debugger≡ menu

stack>advanced patterns / intervals

// Intervals

Sort by start (usually), then sweep: merge, insert, count overlaps. The pattern behind every calendar question.

core idea

Interval problems are array problems wearing a calendar costume: each element is a [start, end] pair, and before you write a single comparison, one question decides the whole solution — what do you sort by. Sort by start and every overlap becomes adjacent, so a single left-to-right sweep can fold ranges together. Sort by end and the earliest-finishing option becomes the provably safe greedy pick, so the same kind of sweep can choose among conflicting ranges instead. Almost everything else in this topic is one of those two sweeps, occasionally with a heap bolted on to track how many ranges are open at once.

sub-shape sort by goal typical trigger
merge start fold overlapping ranges into fewer, wider ones “merge”, “combine”, “insert a meeting”
select end keep the largest non-conflicting subset (or count what you’d drop) “how many can you keep/attend”, “minimum removals”

when to reach for it

  • The input is a list of [start, end] pairs — bookings, log windows, free/busy blocks, “meetings,” version ranges.
  • You need to combine overlapping ranges into fewer, wider ones → sort by start, sweep once.
  • You need to pick the largest non-conflicting subset, or count the minimum you’d remove → sort by end, greedy sweep.
  • You need to know how many ranges are alive at the same instant (rooms, connections, workers) → sort by start, track live count with a heap of end times.
  • Brute force compares every pair of intervals — O(n^2). One sort turns that into a single linear sweep.

universal templates

Merge — sort by start, extend the open run or close it and start a new one:

public int[][] MergeTemplate(int[][] intervals)
{
    Array.Sort(intervals, (a, b) => a[0].CompareTo(b[0]));  // sort by START — merging only cares what runs into what

    var result = new List<int[]> { intervals[0] };
    for (int i = 1; i < intervals.Length; i++)
    {
        var last = result[^1];
        if (intervals[i][0] <= last[1])                // current starts before (or exactly when) last ends
            last[1] = Math.Max(last[1], intervals[i][1]);   // widen the open run to cover both
        else
            result.Add(intervals[i]);                   // no overlap — close the run, start a new one
    }
    return [.. result];
}

Select — sort by end, keep whatever doesn’t conflict with the last thing you kept:

public int SelectTemplate(int[][] intervals)
{
    Array.Sort(intervals, (a, b) => a[1].CompareTo(b[1]));  // sort by END — greedy needs the earliest finisher first

    int kept = 0;
    int lastEnd = int.MinValue;
    foreach (var iv in intervals)
    {
        if (iv[0] >= lastEnd)          // doesn't conflict with the last interval you kept
        {
            kept++;
            lastEnd = iv[1];           // this is now the interval to beat
        }
    }
    return kept;                       // "minimum removals" = intervals.Length - kept
}

Every problem below is one of these two skeletons — sometimes with a min-heap layered on top of the merge template’s start-sort to track how many ranges are open at once, instead of merging them.

the one question to ask

Before you write a comparison, ask: “do I need to combine ranges, or choose among them?” Combine → sort by start. Choose → sort by end. Get that backwards and you’ll write a correct-looking sweep that silently returns the wrong number — the proof behind the select half lives in greedy, and the sort itself is sorting’s bread and butter.

problems

Four problems, and every one of them is the merge template, the select template, or the merge template with a heap standing in for the single running interval:

  1. 01Merge IntervalsmediumLC #56

    Sort by start; extend the current merged interval or start a new one.

  2. 02Insert IntervalmediumLC #57

    Three phases: all-before, merge-overlapping, all-after.

  3. Sort by END — keep the interval that finishes earliest.

  4. 04Meeting Rooms IImediumLC #253

    Min-heap of end times = rooms in use; peak heap size is the answer.

cheat sheet — intervals

recognize it

  • input is a list of [start, end] (or [start, end)) pairs — meetings, bookings, log windows, version ranges
  • "merge overlapping" / "combine ranges" → sort by start
  • "max non-conflicting" / "minimum removals" → sort by end, greedy select
  • "how many rooms/resources needed at once" → sort by start, heap of end times (or the start/end event sweep)

key tricks

  • the whole topic is one sort plus one linear sweep — the sort key (start vs end) IS the design decision, make it first
  • merge check: current.Start <= last.End; select check: current.Start >= lastEnd — note the flipped-feeling inequality
  • touching endpoints (current.Start == last.End) count as overlap when merging, but do NOT conflict when selecting — the two problems disagree with each other on purpose, check the statement
  • Meeting Rooms II = the select template's start-sort, with a min-heap of end times standing in for a single lastEnd
  • the chronological event-sweep (starts[] and ends[] sorted independently, walked with two pointers) reconstructs the same answer as the heap without paying O(log n) per operation

common bugs

  • sorting by the wrong key — merge needs start, select needs end; getting it backwards still compiles and still "runs," just returns a plausible-looking wrong answer
  • < vs <= at the overlap/conflict check — flips whether touching intervals count, and it's easy to copy the wrong convention from a sibling problem in this same topic
  • advancing the "kept" tracker (lastEnd) when you actually dropped an interval — the survivor has to stay the earlier-finishing one, or the greedy guarantee breaks
  • mutating an interval int[] in place (last[1] = ...) without noticing it's a live reference back into the caller's own input array

// connections

  • Sorting for Interviews — step one is always a sort — and start-vs-end is a real decision
  • Greedy — keep-the-earliest-end is a greedy proof you should be able to give
  • Heap & Top-K — Meeting Rooms II tracks live meetings in a min-heap of end times