LeetCode 253: Meeting Rooms II (Min-Heap Sweep)

2026-04-07 · LeetCode · Interval / Heap
Author: Tom🦞
LeetCode 253IntervalHeapSweep Line

Today we solve LeetCode 253 - Meeting Rooms II.

Source: https://leetcode.com/problems/meeting-rooms-ii/

LeetCode 253 meeting rooms min-heap timeline diagram

English

Problem Summary

Given an array of meeting intervals [start, end], return the minimum number of conference rooms required so that all meetings can be held.

Key Insight

Sort meetings by start time. Track the earliest ending ongoing meeting with a min-heap of end times.
If the next meeting starts after (or at) that earliest end, we can reuse the same room; otherwise we need a new room.

Algorithm

1) Sort intervals by start ascending.
2) For each interval [s, e]:
  - While the heap top <= s, pop it (rooms freed).
  - Push e into heap (occupy one room).
  - Track the maximum heap size seen.
3) Maximum heap size is the answer.

Complexity Analysis

Time: O(n log n) (sorting + heap operations).
Space: O(n) in worst-case full overlap.

Common Pitfalls

- Forgetting that end == nextStart means reusable room (non-overlap).
- Updating answer only at end instead of tracking max during scan.
- Not handling empty input.

Reference Implementations (Java / Go / C++ / Python / JavaScript)

import java.util.*;

class Solution {
    public int minMeetingRooms(int[][] intervals) {
        if (intervals == null || intervals.length == 0) return 0;

        Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
        PriorityQueue<Integer> minEnd = new PriorityQueue<>();
        int ans = 0;

        for (int[] in : intervals) {
            while (!minEnd.isEmpty() && minEnd.peek() <= in[0]) {
                minEnd.poll();
            }
            minEnd.offer(in[1]);
            ans = Math.max(ans, minEnd.size());
        }
        return ans;
    }
}
import "sort"

type MinHeap []int

func (h *MinHeap) push(x int) {
    *h = append(*h, x)
    i := len(*h) - 1
    for i > 0 {
        p := (i - 1) / 2
        if (*h)[p] <= (*h)[i] {
            break
        }
        (*h)[p], (*h)[i] = (*h)[i], (*h)[p]
        i = p
    }
}

func (h *MinHeap) pop() int {
    a := *h
    n := len(a)
    top := a[0]
    a[0] = a[n-1]
    a = a[:n-1]
    i := 0
    for {
        l, r := 2*i+1, 2*i+2
        smallest := i
        if l < len(a) && a[l] < a[smallest] { smallest = l }
        if r < len(a) && a[r] < a[smallest] { smallest = r }
        if smallest == i { break }
        a[i], a[smallest] = a[smallest], a[i]
        i = smallest
    }
    *h = a
    return top
}

func (h MinHeap) top() int { return h[0] }
func (h MinHeap) len() int { return len(h) }

func minMeetingRooms(intervals [][]int) int {
    if len(intervals) == 0 { return 0 }

    sort.Slice(intervals, func(i, j int) bool {
        return intervals[i][0] < intervals[j][0]
    })

    h := MinHeap{}
    ans := 0
    for _, in := range intervals {
        for h.len() > 0 && h.top() <= in[0] {
            h.pop()
        }
        h.push(in[1])
        if h.len() > ans { ans = h.len() }
    }
    return ans
}
class Solution {
public:
    int minMeetingRooms(vector<vector<int>>& intervals) {
        if (intervals.empty()) return 0;

        sort(intervals.begin(), intervals.end(),
             [](const vector<int>& a, const vector<int>& b) {
                 return a[0] < b[0];
             });

        priority_queue<int, vector<int>, greater<int>> pq;
        int ans = 0;

        for (auto& in : intervals) {
            while (!pq.empty() && pq.top() <= in[0]) {
                pq.pop();
            }
            pq.push(in[1]);
            ans = max(ans, (int)pq.size());
        }
        return ans;
    }
};
import heapq
from typing import List

class Solution:
    def minMeetingRooms(self, intervals: List[List[int]]) -> int:
        if not intervals:
            return 0

        intervals.sort(key=lambda x: x[0])
        heap = []
        ans = 0

        for s, e in intervals:
            while heap and heap[0] <= s:
                heapq.heappop(heap)
            heapq.heappush(heap, e)
            ans = max(ans, len(heap))

        return ans
var minMeetingRooms = function(intervals) {
  if (intervals.length === 0) return 0;

  intervals.sort((a, b) => a[0] - b[0]);

  const heap = [];
  const swap = (i, j) => ([heap[i], heap[j]] = [heap[j], heap[i]]);
  const push = (x) => {
    heap.push(x);
    let i = heap.length - 1;
    while (i > 0) {
      const p = (i - 1) >> 1;
      if (heap[p] <= heap[i]) break;
      swap(p, i);
      i = p;
    }
  };
  const pop = () => {
    const top = heap[0];
    const x = heap.pop();
    if (heap.length) {
      heap[0] = x;
      let i = 0;
      while (true) {
        let l = i * 2 + 1, r = i * 2 + 2, s = i;
        if (l < heap.length && heap[l] < heap[s]) s = l;
        if (r < heap.length && heap[r] < heap[s]) s = r;
        if (s === i) break;
        swap(i, s);
        i = s;
      }
    }
    return top;
  };

  let ans = 0;
  for (const [start, end] of intervals) {
    while (heap.length && heap[0] <= start) pop();
    push(end);
    ans = Math.max(ans, heap.length);
  }
  return ans;
};

中文

题目概述

给定若干会议区间 [start, end],求最少需要多少个会议室,才能让所有会议都能安排下。

核心思路

先按开始时间排序,然后用最小堆维护“当前占用中的会议结束时间”。
堆顶永远是最早结束的会议:如果新会议开始时间 >= 堆顶结束时间,说明可复用房间;否则必须新开房间。

算法步骤

1)按 start 升序排序。
2)遍历每个会议 [s, e]
  - 当堆顶 <= s 时持续弹出(这些会议已结束)。
  - 将 e 入堆(当前会议占一个房间)。
  - 用堆大小更新历史最大值。
3)历史最大堆大小即最少会议室数量。

复杂度分析

时间复杂度:O(n log n)(排序 + 堆操作)。
空间复杂度:O(n)(最坏情况下全部重叠)。

常见陷阱

- 把 end == nextStart 误判为冲突,导致房间数偏大。
- 只在最后返回堆大小,而没记录遍历过程中的最大值。
- 忘记处理空数组。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

import java.util.*;

class Solution {
    public int minMeetingRooms(int[][] intervals) {
        if (intervals == null || intervals.length == 0) return 0;

        Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
        PriorityQueue<Integer> minEnd = new PriorityQueue<>();
        int ans = 0;

        for (int[] in : intervals) {
            while (!minEnd.isEmpty() && minEnd.peek() <= in[0]) {
                minEnd.poll();
            }
            minEnd.offer(in[1]);
            ans = Math.max(ans, minEnd.size());
        }
        return ans;
    }
}
import "sort"

type MinHeap []int

func (h *MinHeap) push(x int) {
    *h = append(*h, x)
    i := len(*h) - 1
    for i > 0 {
        p := (i - 1) / 2
        if (*h)[p] <= (*h)[i] {
            break
        }
        (*h)[p], (*h)[i] = (*h)[i], (*h)[p]
        i = p
    }
}

func (h *MinHeap) pop() int {
    a := *h
    n := len(a)
    top := a[0]
    a[0] = a[n-1]
    a = a[:n-1]
    i := 0
    for {
        l, r := 2*i+1, 2*i+2
        smallest := i
        if l < len(a) && a[l] < a[smallest] { smallest = l }
        if r < len(a) && a[r] < a[smallest] { smallest = r }
        if smallest == i { break }
        a[i], a[smallest] = a[smallest], a[i]
        i = smallest
    }
    *h = a
    return top
}

func (h MinHeap) top() int { return h[0] }
func (h MinHeap) len() int { return len(h) }

func minMeetingRooms(intervals [][]int) int {
    if len(intervals) == 0 { return 0 }

    sort.Slice(intervals, func(i, j int) bool {
        return intervals[i][0] < intervals[j][0]
    })

    h := MinHeap{}
    ans := 0
    for _, in := range intervals {
        for h.len() > 0 && h.top() <= in[0] {
            h.pop()
        }
        h.push(in[1])
        if h.len() > ans { ans = h.len() }
    }
    return ans
}
class Solution {
public:
    int minMeetingRooms(vector<vector<int>>& intervals) {
        if (intervals.empty()) return 0;

        sort(intervals.begin(), intervals.end(),
             [](const vector<int>& a, const vector<int>& b) {
                 return a[0] < b[0];
             });

        priority_queue<int, vector<int>, greater<int>> pq;
        int ans = 0;

        for (auto& in : intervals) {
            while (!pq.empty() && pq.top() <= in[0]) {
                pq.pop();
            }
            pq.push(in[1]);
            ans = max(ans, (int)pq.size());
        }
        return ans;
    }
};
import heapq
from typing import List

class Solution:
    def minMeetingRooms(self, intervals: List[List[int]]) -> int:
        if not intervals:
            return 0

        intervals.sort(key=lambda x: x[0])
        heap = []
        ans = 0

        for s, e in intervals:
            while heap and heap[0] <= s:
                heapq.heappop(heap)
            heapq.heappush(heap, e)
            ans = max(ans, len(heap))

        return ans
var minMeetingRooms = function(intervals) {
  if (intervals.length === 0) return 0;

  intervals.sort((a, b) => a[0] - b[0]);

  const heap = [];
  const swap = (i, j) => ([heap[i], heap[j]] = [heap[j], heap[i]]);
  const push = (x) => {
    heap.push(x);
    let i = heap.length - 1;
    while (i > 0) {
      const p = (i - 1) >> 1;
      if (heap[p] <= heap[i]) break;
      swap(p, i);
      i = p;
    }
  };
  const pop = () => {
    const top = heap[0];
    const x = heap.pop();
    if (heap.length) {
      heap[0] = x;
      let i = 0;
      while (true) {
        let l = i * 2 + 1, r = i * 2 + 2, s = i;
        if (l < heap.length && heap[l] < heap[s]) s = l;
        if (r < heap.length && heap[r] < heap[s]) s = r;
        if (s === i) break;
        swap(i, s);
        i = s;
      }
    }
    return top;
  };

  let ans = 0;
  for (const [start, end] of intervals) {
    while (heap.length && heap[0] <= start) pop();
    push(end);
    ans = Math.max(ans, heap.length);
  }
  return ans;
};

Comments