Skip to main content

253. Meeting Rooms II

mediumAsked at Robinhood

Given an array of meeting time intervals, return the minimum number of conference rooms required. Robinhood asks this because the same shape — concurrent-task counting — powers capacity planning for trading workers and order-execution pools.

By Alex Chen, Founder, InterviewChamp.AI · Last verified

Source citations

Public interview reports confirming this problem appears in Robinhood loops.

  • Glassdoor (2026-Q1)Robinhood SWE-II onsite reports list Meeting Rooms II as a recurring interval-scheduling round.
  • Blind (2025-11)Robinhood backend trip reports cite the sweepline and min-heap approaches as expected solutions.

Problem

Given an array of meeting time intervals intervals where intervals[i] = [starti, endi], return the minimum number of conference rooms required.

Constraints

  • 1 <= intervals.length <= 10^4
  • 0 <= starti < endi <= 10^6

Examples

Example 1

Input
intervals = [[0,30],[5,10],[15,20]]
Output
2

Explanation: Meetings [5,10] and [15,20] can share one room; [0,30] needs its own.

Example 2

Input
intervals = [[7,10],[2,4]]
Output
1

Approaches

1. Min-heap of end times

Sort by start. For each meeting, evict the heap top if it ends <= current start. Push current end. Heap size at any point is rooms-in-use.

Time
O(n log n)
Space
O(n)
class MinHeap {
  constructor() { this.data = []; }
  size() { return this.data.length; }
  peek() { return this.data[0]; }
  push(v) { this.data.push(v); this._up(this.data.length - 1); }
  pop() { const top = this.data[0]; const last = this.data.pop(); if (this.data.length) { this.data[0] = last; this._down(0); } return top; }
  _up(i) { while (i > 0) { const p = (i - 1) >> 1; if (this.data[p] <= this.data[i]) break; [this.data[p], this.data[i]] = [this.data[i], this.data[p]]; i = p; } }
  _down(i) { const n = this.data.length; while (true) { const l = 2*i+1, r = 2*i+2; let best = i; if (l < n && this.data[l] < this.data[best]) best = l; if (r < n && this.data[r] < this.data[best]) best = r; if (best === i) break; [this.data[best], this.data[i]] = [this.data[i], this.data[best]]; i = best; } }
}

function minMeetingRooms(intervals) {
  if (!intervals.length) return 0;
  intervals.sort((a, b) => a[0] - b[0]);
  const heap = new MinHeap();
  for (const [start, end] of intervals) {
    if (heap.size() > 0 && heap.peek() <= start) heap.pop();
    heap.push(end);
  }
  return heap.size();
}

Tradeoff: Cleanest. Heap stores end times; popping the earliest-ending room when it's free models the room reuse exactly. O(n log n) dominated by sort + heap.

2. Chronological sweepline (two sorted arrays)

Sort starts and ends separately. Walk a pointer for each. When a start < end, increment rooms; otherwise advance the end pointer.

Time
O(n log n)
Space
O(n)
function minMeetingRoomsSweep(intervals) {
  if (!intervals.length) return 0;
  const starts = intervals.map(i => i[0]).sort((a, b) => a - b);
  const ends = intervals.map(i => i[1]).sort((a, b) => a - b);
  let rooms = 0, maxRooms = 0;
  let i = 0, j = 0;
  while (i < starts.length) {
    if (starts[i] < ends[j]) {
      rooms++;
      maxRooms = Math.max(maxRooms, rooms);
      i++;
    } else {
      rooms--;
      j++;
    }
  }
  return maxRooms;
}

Tradeoff: Same O(n log n) but no heap. Common alternative — easier to argue about correctness. Pick whichever you can code bug-free.

3. Event-list sweep

Create +1/-1 events. Sort by time (with end before start on ties). Running sum's max is the answer.

Time
O(n log n)
Space
O(n)
function minMeetingRoomsEvents(intervals) {
  const events = [];
  for (const [s, e] of intervals) {
    events.push([s, 1]);
    events.push([e, -1]);
  }
  events.sort((a, b) => a[0] - b[0] || a[1] - b[1]); // -1 before +1 on ties
  let rooms = 0, max = 0;
  for (const [, delta] of events) {
    rooms += delta;
    if (rooms > max) max = rooms;
  }
  return max;
}

Tradeoff: Most generalizable — works for any 'max concurrent X' problem. The tiebreaker (-1 before +1) is crucial: a meeting ending at t=5 frees a room before another starting at t=5 needs one.

Robinhood-specific tips

Robinhood interviewers care most about the touching-intervals edge case: a meeting ending at 10 and another starting at 10 — do they need separate rooms? Per the LeetCode constraints (start < end), no. State your assumption explicitly. Pick the event-list sweep if you want the most generalizable solution; the heap if you want the cleanest interview answer.

Common mistakes

  • Using <= when checking heap top vs current start in the heap version — should be <= (room is free if the previous meeting ended at or before current start).
  • Forgetting the tiebreaker in the event-list version — same-time end and start would otherwise inflate the count.
  • Sorting by end time instead of start in the heap version — breaks the room-reuse logic.

Follow-up questions

An interviewer at Robinhood may pivot to one of these next:

  • Meeting Rooms (LC 252) — just return true/false whether all fit in one room.
  • Car Pooling (LC 1094) — same shape with passenger counts.
  • Maximum Population Year (LC 1854) — events with +/- on birth/death years.
  • Employee Free Time (LC 759) — invert the schedule across all employees.

Solve it now

Free. No sign-up. Python and JavaScript run instantly in your browser.

Output

Press Run or Cmd+Enter to execute

FAQ

Heap vs sweep — which is preferred?

Both score equally. Heap is cleaner if you have a heap implementation. Sweep is cleaner if you don't. Pick whichever you can write bug-free.

What does the heap actually represent?

End times of currently-in-use rooms. When a new meeting starts, we check the earliest-ending one — if it's free, reuse it (pop + push); otherwise allocate a new room (push only).

Free learning resources

Curated free links for this problem.

Practice these live with InterviewChamp.AI

Drill Meeting Rooms II and other Robinhood interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.

Practice these live with InterviewChamp.AI →