· 6 min read
LeetCode Scheduling Patterns: Hotel/Intervals (Easy & Medium)
All the hotel/scheduling problems in one place: detect overlaps, min rooms, merge/insert intervals, non-overlap, arrows, car pooling. Clean JS templates.
Use these patterns to map hotel/scheduling questions to the right solution fast.
Quick Map
- Can attend all meetings? → sort by start, check overlaps
- Min number of rooms? → sort starts/ends; two pointers to count concurrency
- Merge overlapping intervals → sort by start, merge
- Insert interval → place, merge while overlapping
- Min removals to avoid overlap / max non-overlapping → greedy by end time
- Min arrows to burst balloons → greedy by end time
- Car Pooling feasibility → sweep events (pickup +cap, dropoff -cap)
Can Attend All Meetings (No Overlap) — Easy
Problem. Given an array intervals where intervals[i] = [start_i, end_i] (typically half-open [start, end)), return true if a person can attend all meetings (no overlaps), otherwise false.
Input/Output.
- Input:
intervals: number[][] - Output:
boolean
Constraints. 0 ≤ intervals.length ≤ 1e5, -1e9 ≤ start_i < end_i ≤ 1e9.
Example. [[0,30],[5,10],[15,20]] → false, [[7,10],[2,4]] → true.
function canAttendMeetings(intervals) {
intervals.sort((a, b) => a[0] - b[0]);
for (let i = 1; i < intervals.length; i++) {
if (intervals[i][0] < intervals[i - 1][1]) return false;
}
return true;
}
Why this works
- After sorting by start time, any overlap must appear between a meeting and its immediate predecessor. If
start_i < end_{i-1}, there is a conflict; otherwise all earlier intervals end no later thanend_{i-1}and cannot create a new overlap withintervals[i].
Interval semantics (critical)
- Prefer half-open intervals
[start, end)unless the problem explicitly says inclusive end. - With
[start, end): back-to-back like[10, 20)and[20, 30)are allowed (20 < 20is false). - If ends are inclusive, change the condition to
intervals[i][0] <= intervals[i - 1][1].
Edge cases
- Empty list or single meeting →
true. - Negative times or large coordinates → sorting still works.
- Unsorted input → we sort first; do not assume input order.
Complexity
- Time:
O(n log n)for sorting, thenO(n)scan. - Space:
O(1)extra (in-place sort), orO(n)if you must keep original order.
Alternative (event sweep)
- Build events
(time, delta)with(start, +1)and(end, -1), sort by time then delta, and ensure the running count never exceeds1. Overkill here but generalizes to multi-room.
Quick tests
console.log(
canAttendMeetings([
[0, 30],
[5, 10],
[15, 20],
])
); // false
console.log(
canAttendMeetings([
[7, 10],
[2, 4],
])
); // true
console.log(
canAttendMeetings([
[1, 2],
[2, 3],
[3, 4],
])
); // true (half-open)
console.log(canAttendMeetings([])); // true
Minimum Number of Meeting Rooms (Hotel Rooms) — Medium
Problem. Given intervals of meeting times, return the minimum number of rooms required so that all meetings can be held without conflicts.
Input/Output.
- Input:
intervals: number[][] - Output:
number(minimum rooms)
Constraints. 1 ≤ intervals.length ≤ 1e5, -1e9 ≤ start < end ≤ 1e9.
Example. [[0,30],[5,10],[15,20]] → 2, [[7,10],[2,4]] → 1.
function minMeetingRooms(intervals) {
if (intervals.length === 0) 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 i = 0,
j = 0,
used = 0,
best = 0;
while (i < starts.length) {
if (starts[i] < ends[j]) {
// need a room
used++;
if (used > best) best = used;
i++;
} else {
// free a room
used--;
j++;
}
}
return best;
}
Merge Intervals — Medium
Problem. Given an array of intervals, merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
Input/Output.
- Input:
intervals: number[][] - Output:
number[][](merged)
Constraints. 1 ≤ intervals.length ≤ 1e5, -1e9 ≤ start < end ≤ 1e9.
Example. [[1,3],[2,6],[8,10],[15,18]] → [[1,6],[8,10],[15,18]].
function mergeIntervals(intervals) {
if (intervals.length <= 1) return intervals;
intervals.sort((a, b) => a[0] - b[0]);
const res = [intervals[0].slice()];
for (let i = 1; i < intervals.length; i++) {
const [s, e] = intervals[i];
const last = res[res.length - 1];
if (s <= last[1]) last[1] = Math.max(last[1], e);
else res.push([s, e]);
}
return res;
}
Insert Interval — Medium
Problem. You are given an array of non-overlapping intervals sorted by start time and a new interval newInterval. Insert newInterval into intervals, merging if necessary, and return the resulting array.
Input/Output.
- Input:
intervals: number[][](sorted, non-overlapping),newInterval: [number, number] - Output:
number[][]
Constraints. 0 ≤ intervals.length ≤ 1e5, -1e9 ≤ start < end ≤ 1e9.
Example. intervals = [[1,3],[6,9]], new = [2,5] → [[1,5],[6,9]].
function insertInterval(intervals, newInterval) {
const res = [];
let [ns, ne] = newInterval;
let i = 0;
while (i < intervals.length && intervals[i][1] < ns) res.push(intervals[i++]);
while (i < intervals.length && intervals[i][0] <= ne) {
ns = Math.min(ns, intervals[i][0]);
ne = Math.max(ne, intervals[i][1]);
i++;
}
res.push([ns, ne]);
while (i < intervals.length) res.push(intervals[i++]);
return res;
}
Non-overlapping Intervals (Min Removals) — Medium
Problem. Given a collection of intervals, find the minimum number of intervals you must remove to make the rest non-overlapping.
Input/Output.
- Input:
intervals: number[][] - Output:
number(min removals)
Constraints. 1 ≤ intervals.length ≤ 1e5, -1e9 ≤ start < end ≤ 1e9.
Example. [[1,2],[2,3],[3,4],[1,3]] → 1 (remove [1,3]).
function eraseOverlapIntervals(intervals) {
if (intervals.length <= 1) return 0;
intervals.sort((a, b) => a[1] - b[1]);
let kept = 1;
let end = intervals[0][1];
for (let i = 1; i < intervals.length; i++) {
if (intervals[i][0] >= end) {
kept++;
end = intervals[i][1];
}
}
return intervals.length - kept;
}
Minimum Number of Arrows to Burst Balloons — Medium
Problem. You are given points where points[i] = [x_start, x_end] represents the horizontal diameter of a balloon. One arrow shot vertically at x bursts all balloons with x_start ≤ x ≤ x_end. Return the minimum number of arrows to burst all balloons.
Input/Output.
- Input:
points: number[][] - Output:
number
Constraints. 0 ≤ points.length ≤ 1e5, -1e9 ≤ x_start ≤ x_end ≤ 1e9.
Example. [[10,16],[2,8],[1,6],[7,12]] → 2.
function findMinArrowShots(points) {
if (points.length === 0) return 0;
points.sort((a, b) => a[1] - b[1]);
let arrows = 1;
let end = points[0][1];
for (let i = 1; i < points.length; i++) {
if (points[i][0] > end) {
// no overlap; need new arrow
arrows++;
end = points[i][1];
}
}
return arrows;
}
Car Pooling — Medium
Problem. You are given trips[i] = [numPassengers, from, to], where from and to are locations on a number line. Return true if it is possible to pick up and drop off all passengers for all the given trips using a vehicle with capacity capacity.
Input/Output.
- Input:
trips: number[][],capacity: number - Output:
boolean
Constraints. 1 ≤ trips.length ≤ 1e5, 0 ≤ numPassengers ≤ capacity ≤ 1e9, 0 ≤ from < to ≤ 1e9.
Example. trips = [[2,1,5],[3,3,7]], capacity = 4 → false.
function carPooling(trips, capacity) {
const events = [];
for (const [passengers, start, end] of trips) {
events.push([start, passengers]);
events.push([end, -passengers]);
}
events.sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]));
let cur = 0;
for (const [, delta] of events) {
cur += delta;
if (cur > capacity) return false;
}
return true;
}
Pitfalls
- Use half-open intervals
[start, end)when possible; consistent comparison - Sort by end-time for greedy selection; by start-time for merging
- Equal-time events: process drops before picks to free capacity
- Watch off-by-one in inclusive vs exclusive ends