IntervalsMerge IntervalsSweep LineSortingGreedyScheduling

Interval Problems — The Complete Guide

Master interval manipulation from first principles. Learn to merge, insert, and schedule intervals, recognize overlap patterns instantly, and confidently solve every interval-based interview question.

40 min read10 sections
01

Intuition from Scratch

Why does this pattern exist?

An interval is just a pair [start, end] representing a range — a meeting from 9am to 10am, a booking from Monday to Wednesday, a range of IP addresses. Interval problems ask you to reason about how these ranges relate to each other: do they overlap? Can they be merged? Where are the gaps? How many overlap at the same time?

The fundamental challenge is that intervals can overlap in messy ways. Given a random list of intervals, comparing every pair is O(n²). But here's the key insight: if you sort intervals by start time, overlapping intervals become adjacent in the sorted order. This turns a chaotic comparison problem into a clean linear scan.

That's the entire pattern: sort by start → sweep left to right → make greedy decisions. Every interval problem is a variation of this.

Analogies to Build Intuition

📅

Merging Calendar Events

You have a messy calendar with overlapping meetings. To clean it up, you sort all meetings by start time, then walk through them: if the next meeting starts before the current one ends, they overlap — merge them into one longer block. If not, it's a separate meeting. That's Merge Intervals.

🏨

Hotel Room Booking

A hotel needs to know the maximum number of guests at any time. Each booking is an interval [check-in, check-out]. Sort all check-ins and check-outs on a timeline, then sweep through: +1 at each check-in, -1 at each check-out. The running total tells you how many rooms are occupied. That's the sweep line technique.

🎯

Popping Balloons on a Number Line

Balloons are placed at intervals on a number line. You want to pop as many as possible with the fewest arrows. Sort balloons by end point, shoot at the earliest ending balloon — this arrow also pops any balloon that overlaps with it. That's the greedy interval scheduling approach.

What kind of problems does it solve?

Interval techniques are your go-to when:

  • You need to merge overlapping intervals into non-overlapping ones
  • You need to insert a new interval into a sorted list and merge if needed
  • You need to find the maximum number of overlapping intervals at any point
  • You need to determine if a person can attend all meetings (no overlaps)
  • You need to find the minimum number of resources (rooms, servers) to handle all intervals
  • You need to remove minimum intervals to eliminate all overlaps
  • You need to find free time / gaps between intervals

The Two Overlap Conditions — Know These Cold

Overlap Detectiontext
Two intervals [a, b] and [c, d] (where ab and cd):

OVERLAP if:  a <= d AND c <= b
             (one starts before the other ends, AND vice versa)

NO OVERLAP if:  b < c OR d < a
                (one ends before the other starts)

After sorting by start time (ac guaranteed):
  OVERLAP if:  c <= b   (next starts before current ends)
  NO OVERLAP:  c > b    (next starts after current ends)

This simplification after sorting is why we ALWAYS sort first.

The core insight

Interval problems are sorting problems in disguise. Once sorted by start time, overlapping intervals are always adjacent. You never need to look backwards. This turns O(n²) pairwise comparison into O(n log n) sort + O(n) scan = O(n log n) total.

02

Pattern Recognition

Interval problems are usually easy to spot — the input is literally a list of [start, end] pairs. The real skill is recognizing whichinterval technique to apply.

Keywords & Signals in the Problem Statement

Use Interval techniques when you see...

  • "Merge overlapping intervals"
  • "Insert interval" into a list of non-overlapping intervals
  • "Meeting rooms" — can a person attend all? How many rooms needed?
  • "Minimum number of arrows / points to cover all intervals"
  • "Remove minimum intervals to make non-overlapping"
  • "Free time" or "gaps" between schedules
  • "Maximum number of events at the same time"
  • Input is a list of [start, end] pairs
  • "Booking" or "scheduling" problems
  • "Overlapping" appears in the problem description

Don't use Interval techniques when...

  • The ranges are on a 2D grid (might need sweep line + segment tree)
  • You need subarray sums (use prefix sum or sliding window)
  • The 'intervals' are actually indices into an array (might be two pointers)
  • The problem involves circular ranges without clear linearization
  • You need to find a specific value within ranges (might be binary search)
  • The intervals represent edges in a graph (use graph algorithms)

Interval Techniques vs. Similar Patterns

PatternWhen to UseKey Difference
Interval Merge/SortMerge overlapping ranges, insert intervals, check conflictsSort by start → linear scan. Greedy decisions based on overlap
Sweep LineCount max overlaps, find busy/free periodsConvert intervals to events (+1/-1), sort events, scan with running count
Greedy SchedulingMaximize non-overlapping intervals, minimize removals/arrowsSort by END time, greedily pick earliest-ending non-conflicting interval
Sliding WindowContiguous subarray with a constraintWindow moves over array indices, not arbitrary [start, end] ranges
Difference ArrayApply range updates efficientlyIntervals represent updates to an array, not standalone ranges to merge

Sort by Start vs Sort by End — When?

Sort ByWhenWhy
Start timeMerge intervals, insert interval, meeting rooms, free timeYou process intervals in chronological order and merge/extend as you go
End timeMax non-overlapping intervals, min arrows, min removalsGreedy: pick the interval that ends earliest → leaves most room for future intervals

The sorting question

Before coding any interval problem, ask: "Should I sort by start or end?" If you're merging or scanning chronologically → sort by start. If you're greedily selecting non-overlapping intervals → sort by end. Getting this wrong leads to incorrect greedy choices.

03

Brute Force → Optimized Thinking

Let's walk through the thinking evolution using the classic example: Merge Intervals — given a list of intervals, merge all overlapping intervals and return the non-overlapping result.

1

Brute Force — Compare Every Pair

O(n²) time · O(n) space

For each interval, check if it overlaps with any other interval. If it does, merge them and restart the scan (because the merged interval might now overlap with something else). Repeat until no more merges are possible.

Brute Forcetypescript
function merge(intervals: number[][]): number[][] {
  const result = [...intervals];
  let merged = true;

  while (merged) {
    merged = false;
    for (let i = 0; i < result.length; i++) {
      for (let j = i + 1; j < result.length; j++) {
        // Check overlap: a.start <= b.end AND b.start <= a.end
        if (result[i][0] <= result[j][1] && result[j][0] <= result[i][1]) {
          // Merge: take min start, max end
          result[i] = [
            Math.min(result[i][0], result[j][0]),
            Math.max(result[i][1], result[j][1])
          ];
          result.splice(j, 1); // remove j
          merged = true;
          break;
        }
      }
      if (merged) break; // restart outer loop
    }
  }

  return result;
}
// Problem: O(n²) per pass, potentially O(n) passes = O(n³) worst case.
// We're comparing every pair and restarting after each merge.
2

Key Observation — Sorting Makes Overlaps Adjacent

Thinking step

If we sort intervals by start time, any interval that overlaps with the current one MUST be the next one in sorted order. We never need to look backwards or restart. This is because after sorting, if interval B doesn't overlap with A, then nothing after B can overlap with A either (they all start even later).

The Insighttext
Unsorted: [[1,3], [8,10], [2,6], [15,18]]
Which pairs overlap? Need to check all 6 pairs.

Sorted by start: [[1,3], [2,6], [8,10], [15,18]]
  → [1,3] and [2,6] overlap (23) → merge to [1,6]
  → [1,6] and [8,10]? No (8 > 6) → done with [1,6]
  → [8,10] and [15,18]? No (15 > 10) → done

Result: [[1,6], [8,10], [15,18]]

After sorting, we only compare ADJACENT intervals.
One pass. No restarts. O(n) after the O(n log n) sort.
3

Optimal — Sort + Single Pass Merge

O(n log n) time · O(n) space

Sort by start time. Initialize result with the first interval. For each subsequent interval: if it overlaps with the last interval in result (its start ≤ result's last end), extend the end. Otherwise, it's a new non-overlapping interval — push it to result.

Sort + Merge — Optimaltypescript
function merge(intervals: number[][]): number[][] {
  // Step 1: Sort by start time
  intervals.sort((a, b) => a[0] - b[0]);

  const result: number[][] = [intervals[0]];

  for (let i = 1; i < intervals.length; i++) {
    const last = result[result.length - 1];
    const curr = intervals[i];

    if (curr[0] <= last[1]) {
      // Overlap → extend the end of the last merged interval
      last[1] = Math.max(last[1], curr[1]);
    } else {
      // No overlap → start a new interval
      result.push(curr);
    }
  }

  return result;
}
// O(n log n) for sort + O(n) for scan = O(n log n) total.
// Each interval is processed exactly once. Clean and optimal.

Why Does Each Optimization Work?

1

Brute → Sorted

Sorting by start time guarantees that if interval B doesn't overlap with A, nothing after B can overlap with A either (they all start later). This eliminates the need for pairwise comparison and restarts.

2

Why a Single Pass Works

After sorting, we maintain a 'current merged interval' (the last one in result). Each new interval either extends it (overlap) or starts a new one (no overlap). We never need to go back because the sorted order guarantees all overlaps with the current interval are consecutive.

3

The General Principle

Almost every interval problem follows this pattern: sort to bring related intervals together, then make a single greedy pass. The sort is the key enabler — it turns a 2D comparison problem into a 1D scan.

The thinking process matters more than the code

In interviews, explain: "Unsorted intervals can overlap in any order, making pairwise comparison O(n²). But if I sort by start time, overlapping intervals become adjacent. I can merge in a single pass by comparing each interval with the last merged one. This gives me O(n log n)."

04

Core Templates

Interval problems boil down to three core templates. Memorize these — every problem is a variation of one of them.

Template 1: Merge Overlapping Intervals

Sort by start. Walk through, extending the current interval when overlap is found. Used for merge intervals, insert interval, and finding gaps.

Merge Intervals Templatetypescript
function mergeIntervals(intervals: number[][]): number[][] {
  intervals.sort((a, b) => a[0] - b[0]); // sort by start

  const merged: number[][] = [intervals[0]];

  for (let i = 1; i < intervals.length; i++) {
    const last = merged[merged.length - 1];
    const curr = intervals[i];

    if (curr[0] <= last[1]) {
      // Overlap → extend end
      last[1] = Math.max(last[1], curr[1]);
    } else {
      // No overlap → new interval
      merged.push(curr);
    }
  }

  return merged;
}
// Variations:
// - Insert interval: add new interval to list, then merge
// - Find gaps: when curr[0] > last[1], the gap is [last[1], curr[0]]
// - Intersection: instead of extending, take the overlap portion

Template 2: Sweep Line (Event-Based)

Convert each interval into two events: +1 at start, -1 at end. Sort all events, then sweep through with a running counter. Used for counting max overlaps, meeting rooms, and busy/free periods.

Sweep Line Templatetypescript
function maxOverlaps(intervals: number[][]): number {
  // Create events: [time, type] where +1 = start, -1 = end
  const events: [number, number][] = [];

  for (const [start, end] of intervals) {
    events.push([start, 1]);   // interval starts
    events.push([end, -1]);    // interval ends
  }

  // Sort by time. If same time, process ends (-1) before starts (+1)
  // (an interval ending at time T doesn't overlap with one starting at T)
  events.sort((a, b) => a[0] - b[0] || a[1] - b[1]);

  let active = 0;
  let maxActive = 0;

  for (const [, type] of events) {
    active += type;
    maxActive = Math.max(maxActive, active);
  }

  return maxActive;
}
// Variations:
// - Meeting rooms II: maxActive = minimum rooms needed
// - Find the time with max overlaps: track the time when maxActive updates
// - Free time: periods where active === 0

Template 3: Greedy Interval Scheduling (Sort by End)

Sort by end time. Greedily select the interval that ends earliest and doesn't conflict with the last selected one. Used for maximizing non-overlapping intervals, minimum arrows, and minimum removals.

Greedy Scheduling Templatetypescript
function maxNonOverlapping(intervals: number[][]): number {
  // Sort by END time (critical for greedy correctness)
  intervals.sort((a, b) => a[1] - b[1]);

  let count = 0;
  let lastEnd = -Infinity;

  for (const [start, end] of intervals) {
    if (start >= lastEnd) {
      // No conflict → select this interval
      count++;
      lastEnd = end;
    }
    // else: skip (overlaps with last selected)
  }

  return count;
}
// Why sort by end? The interval that ends earliest leaves the most
// room for future intervals. This greedy choice is provably optimal.
//
// Variations:
// - Min removals to make non-overlapping: n - maxNonOverlapping
// - Min arrows to burst balloons: same logic (arrow at lastEnd pops all overlapping)
// - Erase overlap intervals: count overlapping ones to remove

Quick Reference: Which Template?

Problem TypeSort ByTemplate
Merge overlapping intervalsStart timeTemplate 1 — extend or push
Insert interval into sorted listStart time (already sorted)Template 1 — find position, merge
Find gaps / free timeStart timeTemplate 1 — gaps between merged intervals
Max simultaneous overlapsEvent timeTemplate 2 — sweep line +1/-1
Minimum meeting roomsEvent timeTemplate 2 — max active count
Max non-overlapping intervalsEnd timeTemplate 3 — greedy select earliest end
Min removals for no overlapEnd timeTemplate 3 — n minus max non-overlapping
Min arrows to burst balloonsEnd timeTemplate 3 — greedy arrow placement

The memory trick

Merging? → Sort by start, extend end. Counting overlaps? → Sweep line with +1/-1 events. Selecting/removing? → Sort by end, greedy pick. Three templates, three sort strategies. That's the entire pattern.

05

Variations & Sub-Patterns

The three templates cover the basics, but real interview problems add twists. Here are the most important variations.

VariationCore TechniqueClassic Example
Merge IntervalsSort by start → extend or pushMerge Intervals (LC 56)
Insert IntervalThree-phase: before, overlapping, afterInsert Interval (LC 57)
Interval IntersectionTwo pointers on two sorted lists, take overlap portionInterval List Intersections (LC 986)
Meeting Rooms (conflict check)Sort by start, check if any consecutive pair overlapsMeeting Rooms (LC 252)
Meeting Rooms II (min rooms)Sweep line or min-heap of end timesMeeting Rooms II (LC 253)
Non-Overlapping IntervalsSort by end, greedy select → removals = n - selectedNon-overlapping Intervals (LC 435)
Minimum ArrowsSort by end, greedy arrow at earliest endMinimum Number of Arrows (LC 452)
Employee Free TimeMerge all intervals across employees, find gapsEmployee Free Time (LC 759)

Deep Dive: Insert Interval (Three-Phase Approach)

Insert Interval is trickier than Merge because the input is already sorted and non-overlapping. The cleanest approach splits the work into three phases: intervals entirely before the new one, intervals that overlap with it, and intervals entirely after it.

Problems mentioned above

Insert Interval — Three Phasestypescript
function insert(
  intervals: number[][],
  newInterval: number[]
): number[][] {
  const result: number[][] = [];
  let i = 0;
  const n = intervals.length;

  // Phase 1: Add all intervals that end BEFORE newInterval starts
  while (i < n && intervals[i][1] < newInterval[0]) {
    result.push(intervals[i]);
    i++;
  }

  // Phase 2: Merge all overlapping intervals with newInterval
  while (i < n && intervals[i][0] <= newInterval[1]) {
    newInterval[0] = Math.min(newInterval[0], intervals[i][0]);
    newInterval[1] = Math.max(newInterval[1], intervals[i][1]);
    i++;
  }
  result.push(newInterval); // push the merged interval

  // Phase 3: Add all intervals that start AFTER newInterval ends
  while (i < n) {
    result.push(intervals[i]);
    i++;
  }

  return result;
}
// Phase 1: intervals[i][1] < newInterval[0] → entirely before
// Phase 2: intervals[i][0] <= newInterval[1] → overlaps → merge
// Phase 3: everything remaining → entirely after

Deep Dive: Interval List Intersections (Two Pointers)

Given two sorted lists of non-overlapping intervals, find their intersection. Use two pointers — one per list. At each step, compute the overlap (if any) and advance the pointer whose interval ends first.

Interval List Intersectionstypescript
function intervalIntersection(
  firstList: number[][],
  secondList: number[][]
): number[][] {
  const result: number[][] = [];
  let i = 0, j = 0;

  while (i < firstList.length && j < secondList.length) {
    const lo = Math.max(firstList[i][0], secondList[j][0]);
    const hi = Math.min(firstList[i][1], secondList[j][1]);

    if (lo <= hi) {
      result.push([lo, hi]); // valid intersection
    }

    // Advance the pointer whose interval ends first
    if (firstList[i][1] < secondList[j][1]) {
      i++;
    } else {
      j++;
    }
  }

  return result;
}
// Why advance the earlier-ending interval? It can't intersect with
// anything else in the other list (the other list is sorted, so
// future intervals start even later).

Meeting Rooms II — Two approaches

You can solve Meeting Rooms II with either sweep line (Template 2) or a min-heap. The heap approach: sort by start, maintain a min-heap of end times. For each meeting, if it starts after the earliest end → reuse that room (pop and push new end). Otherwise → need a new room (just push). Heap size at the end = min rooms needed.

06

Visual Walkthrough

Let's trace through three different interval techniques to see how each one works step by step.

Merge Intervals — Step by Step

Merge Intervals — Tracetext
Input: [[1,3], [8,10], [2,6], [15,18]]

Step 1: Sort by start → [[1,3], [2,6], [8,10], [15,18]]

Step 2: Initialize result = [[1,3]]

i=1: curr=[2,6], last=[1,3]
     23? YESoverlap! Extend: last = [1, max(3,6)] = [1,6]
     result = [[1,6]]

i=2: curr=[8,10], last=[1,6]
     86? NOno overlap. Push [8,10]
     result = [[1,6], [8,10]]

i=3: curr=[15,18], last=[8,10]
     1510? NOno overlap. Push [15,18]
     result = [[1,6], [8,10], [15,18]]

Output: [[1,6], [8,10], [15,18]]

Timeline visualization:
  [1---3]
     [2------6]
                  [8--10]
                              [15--18]
  ─────────────────────────────────────
  [1--------6]   [8--10]     [15--18]  ← merged

Sweep Line (Meeting Rooms II) — Step by Step

Meeting Rooms II — Sweep Line Tracetext
Meetings: [[0,30], [5,10], [15,20]]

Step 1: Create events
  [0, +1]  — meeting 1 starts
  [30, -1] — meeting 1 ends
  [5, +1]  — meeting 2 starts
  [10, -1] — meeting 2 ends
  [15, +1] — meeting 3 starts
  [20, -1] — meeting 3 ends

Step 2: Sort by time (ends before starts if same time)
  [0, +1], [5, +1], [10, -1], [15, +1], [20, -1], [30, -1]

Step 3: Sweep
  t=0:  active = 0+1 = 1  maxActive = 1
  t=5:  active = 1+1 = 2  maxActive = 2
  t=10: active = 2-1 = 1
  t=15: active = 1+1 = 2  maxActive = 2
  t=20: active = 2-1 = 1
  t=30: active = 1-1 = 0

Answer: 2 rooms needed (at times 5-10 and 15-20, two meetings overlap)

Timeline:
  Room 1: [0=========================30]
  Room 2:      [5===10]  [15===20]
  ──────────────────────────────────────
  Active:  1    2    1    2    1    0

Greedy Scheduling (Non-Overlapping) — Step by Step

Non-Overlapping Intervals — Greedy Tracetext
Input: [[1,2], [2,3], [3,4], [1,3]]
Goal: Remove minimum intervals to make all non-overlapping.

Step 1: Sort by END time → [[1,2], [2,3], [1,3], [3,4]]

Step 2: Greedy select (pick earliest-ending non-conflicting)
  lastEnd = -∞

  [1,2]: 1 ≥ -∞? YESselect. count=1, lastEnd=2
  [2,3]: 22?  YESselect. count=2, lastEnd=3
  [1,3]: 13?  NOskip (overlaps with last selected)
  [3,4]: 33?  YESselect. count=3, lastEnd=4

Max non-overlapping = 3
Min removals = 4 - 3 = 1 (remove [1,3])

Why sort by end? [1,3] ends later than [2,3], so keeping [2,3]
leaves more room for [3,4]. Earliest end = most room for future.

Timeline:
  [1-2] [2-3] [3-4]  ← selected (no overlaps)
  [1----3]            ← removed (overlaps with [2,3])
  ──────────────────
07

Practice Problems

These 7 problems are carefully ordered from easy to hard. Each one teaches a different interval technique. Solve them in order.

1

LC 252. Meeting Rooms

Easy

Why this pattern:

The simplest interval problem: can a person attend all meetings? Sort by start time, check if any consecutive pair overlaps. If intervals[i].start < intervals[i-1].end → conflict.

Key idea: Sort by start. Scan pairs: if any meeting starts before the previous one ends, return false. This is just 'check if any intervals overlap' — the foundation for all interval problems.

2

LC 56. Merge Intervals

Medium

Why this pattern:

The canonical interval problem (Template 1). Sort by start, then sweep: if the current interval overlaps with the last merged one, extend the end. Otherwise, push a new interval.

Key idea: Sort by start. Maintain result array. For each interval: if curr.start ≤ last.end → overlap, extend last.end = max(last.end, curr.end). Else → push curr. One pass after sorting.

3

LC 57. Insert Interval

Medium

Why this pattern:

Three-phase approach on an already-sorted list. Phase 1: add intervals before the new one. Phase 2: merge all overlapping intervals with the new one. Phase 3: add intervals after.

Key idea: Walk through the sorted list. While intervals end before newInterval starts → add to result. While intervals overlap with newInterval → merge (extend newInterval). Add newInterval. Add remaining intervals.

4

LC 435. Non-overlapping Intervals

Medium

Why this pattern:

Greedy scheduling (Template 3). Find the maximum number of non-overlapping intervals, then removals = n - max. Sort by END time and greedily pick the earliest-ending non-conflicting interval.

Key idea: Sort by end. Greedily select: if curr.start ≥ lastEnd → select, update lastEnd. Count selected. Answer = n - count. Sorting by end is critical — it ensures the greedy choice is optimal.

5

LC 253. Meeting Rooms II

Medium

Why this pattern:

Sweep line (Template 2) or min-heap approach. Count the maximum number of overlapping meetings at any point in time — that's the minimum number of rooms needed.

Key idea: Sweep line: create +1 events at starts, -1 at ends. Sort events. Sweep with running count. Max count = answer. Alternatively: sort by start, use a min-heap of end times. If earliest end ≤ current start → reuse room (pop). Always push current end. Heap size = rooms.

6

LC 452. Minimum Number of Arrows to Burst Balloons

Medium

Why this pattern:

Greedy scheduling variant (Template 3). Each arrow is placed at a point. Sort balloons by end. Place arrow at the earliest end — it bursts all balloons that overlap with that point.

Key idea: Sort by end. For each balloon: if its start > lastArrow position → need a new arrow at this balloon's end. Otherwise → the existing arrow already covers it. Count arrows.

7

LC 986. Interval List Intersections

Medium

Why this pattern:

Two-pointer approach on two sorted interval lists. At each step, compute the overlap (max of starts, min of ends). If valid overlap, add it. Advance the pointer whose interval ends first.

Key idea: Two pointers i, j. Overlap = [max(a.start, b.start), min(a.end, b.end)]. If lo ≤ hi → valid intersection. Advance the pointer with the smaller end (it can't intersect with anything else in the other list).

Practice strategy

For each problem: (1) Identify which template applies (merge, sweep line, or greedy). (2) Determine the sort order (start or end). (3) Write the overlap condition. (4) After solving, write: "This is [template] because [I need to merge / count overlaps / select non-overlapping]."

08

Common Mistakes

These are the traps that catch people on interval problems. Learn them here so you don't learn them in an interview.

🔀

Sorting by start when you should sort by end (or vice versa)

You sort by start for a greedy scheduling problem. The greedy choice becomes incorrect — you might select a long interval that blocks many shorter ones.

Merging/scanning → sort by start. Greedy selection (max non-overlapping, min arrows) → sort by end. The sort order determines whether the greedy choice is optimal. Get this right before coding.

📐

Off-by-one in overlap condition (< vs ≤)

You use curr.start < last.end when the problem considers touching intervals [1,2] and [2,3] as overlapping. Or you use ≤ when they shouldn't overlap.

Read the problem carefully: do intervals [1,2] and [2,3] overlap? If the problem says 'meetings at [1,2] and [2,3] don't conflict' → use strict <. If they do conflict → use ≤. This varies by problem.

🔄

Forgetting to use Math.max when extending the merged interval

You set last.end = curr.end instead of last.end = Math.max(last.end, curr.end). This fails when the current interval is entirely contained within the last one (e.g., [1,10] and [2,5]).

Always use Math.max(last.end, curr.end) when merging. The current interval might end before the last one — you need to keep the larger end. Draw [1,10] and [2,5] to see why.

Wrong event ordering in sweep line

When two events happen at the same time (one start, one end), you process the start before the end. This overcounts overlaps — an interval ending at time T and one starting at T shouldn't be counted as overlapping.

When sorting events with the same time, process ends (-1) before starts (+1). This ensures that an interval ending at T frees its resource before a new one starting at T claims it. Sort by (time, type) where end < start.

📊

Not handling the empty input or single interval case

You access intervals[0] without checking if the array is empty. Or your loop starts at i=1 but the array has only one element.

Add an early return: if (intervals.length <= 1) return intervals. Or initialize your result with intervals[0] only after checking the array isn't empty. Always test with 0 and 1 intervals.

🎯

Mutating the input array during merge

You modify intervals in-place while iterating, causing skipped elements or incorrect merges. Or you modify the newInterval reference in Insert Interval and lose track of the original.

Build a separate result array. Never modify the input while iterating over it. For Insert Interval, it's fine to modify newInterval (you're building it up), but don't modify the original intervals array.

09

Interview Strategy

Interval problems are popular in FAANG interviews because they test sorting intuition, greedy reasoning, and edge case handling. Here's how to approach them.

The 5-Step Interview Flow

1

Clarify the Overlap Definition

'Do intervals [1,2] and [2,3] overlap? Are the endpoints inclusive or exclusive? Can intervals have zero length [5,5]?' This determines your < vs ≤ condition and is the #1 source of bugs.

2

Identify the Template

'I need to merge overlapping intervals → sort by start, linear merge. I need to count max overlaps → sweep line. I need to maximize non-overlapping → sort by end, greedy.' Name the technique explicitly.

3

State the Sort Order and Why

'I'll sort by start time because I need to process intervals chronologically and merge adjacent overlaps.' Or: 'I'll sort by end time because the greedy choice is to pick the interval that ends earliest.' Explain the reasoning.

4

Code the Overlap Condition Carefully

Write the overlap check as a clear condition: curr[0] <= last[1] for merge, or start >= lastEnd for greedy. Add a comment. This is where bugs hide — be explicit.

5

Test Edge Cases

Trace through: (1) empty input, (2) single interval, (3) all intervals overlap into one, (4) no intervals overlap, (5) one interval contained inside another [1,10] and [3,5]. State complexity: O(n log n) time, O(n) space.

Common Follow-Up Questions

Follow-UpHow to Handle
"What if intervals are streaming (not all available upfront)?"Use a balanced BST or sorted set to maintain intervals. Insert each new interval and merge with neighbors. This gives O(log n) per insertion instead of re-sorting.
"What if you need to support add AND remove interval?"Use a balanced BST (like a TreeMap) keyed by start time. Add: insert and merge with neighbors. Remove: find the interval, split if partially removed. More complex but same core logic.
"Can you do it without sorting?"For merge: you could use a bucket/counting approach if the range is bounded, but sorting is the standard and expected approach. For sweep line: you need sorted events, so sorting is inherent.
"What if intervals are weighted (each has a value)?"This becomes a weighted job scheduling problem. Sort by end, use DP: for each interval, either take it (value + best non-overlapping before it) or skip it. Binary search to find the last non-overlapping interval.
"Extend to 2D rectangles?"Use sweep line on one axis (e.g., x) and a segment tree or balanced BST on the other axis (y). This is an advanced technique — mention it to show breadth of knowledge.
"What's the space complexity?"O(n) for the result array (or O(n) for the events array in sweep line). The sort is O(log n) extra space (or O(n) depending on the sort algorithm). Mention that the input sort is in-place if allowed.

The meta-skill

Interval problems test your ability to reduce a 2D problem (start AND end) to a 1D scan by sorting. The interviewer wants to see: (1) You immediately think "sort first." (2) You choose the right sort key (start vs end). (3) You handle the overlap condition precisely. (4) You reason about why the greedy choice is correct. Practice explaining the sort-then-scan paradigm out loud.

10

Summary & Cheat Sheet

Pin this section. Review it before mock interviews and contests.

Quick Revision Cheat Sheet

Core idea: Sort intervals to make overlaps adjacent → single-pass greedy scan. O(n log n)

Overlap condition: After sorting by start: curr.start ≤ last.end → overlap. Check < vs ≤ per problem

Merge template: Sort by start. Extend last.end = max(last.end, curr.end) on overlap. Push new interval otherwise

Sweep line: Convert to events: +1 at start, -1 at end. Sort events. Sweep with running count. Max count = answer

Greedy scheduling: Sort by END. Pick earliest-ending non-conflicting interval. Provably optimal for max non-overlapping

Insert interval: Three phases: before (end < new.start), overlapping (start ≤ new.end), after. Merge in phase 2

Intersection: Two pointers. Overlap = [max(starts), min(ends)]. Valid if lo ≤ hi. Advance earlier-ending pointer

Min removals: n - maxNonOverlapping. Sort by end, greedy count, subtract from total

Meeting rooms: Conflict check: sort by start, check consecutive. Min rooms: sweep line or min-heap of end times

Math.max trap: Always use max(last.end, curr.end) when merging — current interval might be contained inside the last one

Event ordering: Same-time events: process ends before starts. Sort by (time, type) where -1 < +1

Mental trigger: See [start, end] pairs → sort first. Merging → sort by start. Selecting → sort by end. Counting → sweep line

Decision Flowchart

Which Interval Technique? — Decision Treetext
What does the problem ask?
├── Merge overlapping intervals into non-overlapping?
│   → Sort by START. Sweep: extend or push. (Template 1)
├── Insert a new interval into a sorted list?
│   → Three phases: before, overlap (merge), after. (Template 1 variant)
├── Find intersection of two interval lists?
│   → Two pointers. Overlap = [max starts, min ends]. Advance earlier end.
├── Check if any intervals overlap (conflict)?
│   → Sort by start. Check if any consecutive pair overlaps.
├── Count max simultaneous overlaps / min resources?
│   → Sweep line: +1 at start, -1 at end. Sort events. Max running count.
│   → Or: min-heap of end times (Meeting Rooms II).
├── Maximize non-overlapping intervals?
│   → Sort by END. Greedy: pick earliest-ending non-conflicting. (Template 3)
├── Minimize removals to eliminate overlaps?
│   → Same as above: removals = n - maxNonOverlapping.
├── Minimum arrows / points to cover all intervals?
│   → Sort by END. Greedy: place arrow at earliest end. (Template 3 variant)
└── Find gaps / free time between intervals?
Merge all intervals (Template 1), then gaps = spaces between merged.

One last thing

Interval problems are one of the most predictable patterns in interviews. There are only three templates and the problems are variations of the same core idea: sort, then scan. The tricky part is choosing the right sort key and getting the overlap condition exactly right. Solve the 7 problems in Section 07, pay attention to the < vs ≤ distinction, and you'll handle any interval question with confidence.