Schedule Tasks on Minimum Machines
curriculum variant of meeting rooms — schedule interval-style tasks across the fewest possible machines.
Medium
Time
O(n log n) Space O(n) 4 min read
heaps intervals
Problem#
(curriculum variant.) Given a list of tasks, each with (start, end), return the minimum number of machines needed to run all tasks without overlap on any machine.
Examples#
[(1,4),(2,3),(3,5)]→2
Constraints#
1 <= n <= 10^5.
Approach#
Identical to Meeting Rooms II: sort by start, maintain a min-heap of end times of in-use machines. For each task, pop the heap top if it ≤ task start (machine free), else add a new machine.
Solution#
int minMachines(vector<pair<int,int>>& tasks) { sort(tasks.begin(), tasks.end()); priority_queue<int, vector<int>, greater<int>> ends; for (auto& [s, e] : tasks) { if (!ends.empty() && ends.top() <= s) ends.pop(); ends.push(e); } return ends.size();}import ( "container/heap" "sort")
type minHeap []int
func (h minHeap) Len() int { return len(h) }func (h minHeap) Less(i, j int) bool { return h[i] < h[j] }func (h minHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }func (h *minHeap) Push(x interface{}) { *h = append(*h, x.(int)) }func (h *minHeap) Pop() interface{} { old := *h n := len(old) x := old[n-1] *h = old[:n-1] return x}
func minMachines(tasks [][2]int) int { sort.Slice(tasks, func(i, j int) bool { return tasks[i][0] < tasks[j][0] }) ends := &minHeap{} heap.Init(ends) for _, t := range tasks { s, e := t[0], t[1] if ends.Len() > 0 && (*ends)[0] <= s { heap.Pop(ends) } heap.Push(ends, e) } return ends.Len()}import heapqfrom typing import List, Tuple
class Solution: def minMachines(self, tasks: List[Tuple[int, int]]) -> int: tasks.sort() ends: List[int] = [] for s, e in tasks: if ends and ends[0] <= s: heapq.heappop(ends) heapq.heappush(ends, e) return len(ends)class MinHeap { constructor() { this.h = []; } size() { return this.h.length; } peek() { return this.h[0]; } push(v) { this.h.push(v); let i = this.h.length - 1; while (i > 0) { const p = (i - 1) >> 1; if (this.h[p] <= this.h[i]) break; [this.h[p], this.h[i]] = [this.h[i], this.h[p]]; i = p; } } pop() { const top = this.h[0]; const last = this.h.pop(); if (this.h.length) { this.h[0] = last; let i = 0; const n = this.h.length; while (true) { const l = 2 * i + 1, r = 2 * i + 2; let s = i; if (l < n && this.h[l] < this.h[s]) s = l; if (r < n && this.h[r] < this.h[s]) s = r; if (s === i) break; [this.h[i], this.h[s]] = [this.h[s], this.h[i]]; i = s; } } return top; }}
function minMachines(tasks) { tasks.sort((a, b) => a[0] - b[0]); const ends = new MinHeap(); for (const [s, e] of tasks) { if (ends.size() > 0 && ends.peek() <= s) ends.pop(); ends.push(e); } return ends.size();}class Solution { public int minMachines(int[][] tasks) { Arrays.sort(tasks, (a, b) -> a[0] - b[0]); PriorityQueue<Integer> ends = new PriorityQueue<>(); for (int[] t : tasks) { int s = t[0], e = t[1]; if (!ends.isEmpty() && ends.peek() <= s) ends.poll(); ends.offer(e); } return ends.size(); }}class MinHeap { private h: number[] = []; size(): number { return this.h.length; } peek(): number { return this.h[0]; } push(v: number): void { this.h.push(v); let i = this.h.length - 1; while (i > 0) { const p = (i - 1) >> 1; if (this.h[p] <= this.h[i]) break; [this.h[p], this.h[i]] = [this.h[i], this.h[p]]; i = p; } } pop(): number { const top = this.h[0]; const last = this.h.pop()!; if (this.h.length) { this.h[0] = last; let i = 0; const n = this.h.length; while (true) { const l = 2 * i + 1, r = 2 * i + 2; let s = i; if (l < n && this.h[l] < this.h[s]) s = l; if (r < n && this.h[r] < this.h[s]) s = r; if (s === i) break; [this.h[i], this.h[s]] = [this.h[s], this.h[i]]; i = s; } } return top; }}
function minMachines(tasks: [number, number][]): number { tasks.sort((a, b) => a[0] - b[0]); const ends = new MinHeap(); for (const [s, e] of tasks) { if (ends.size() > 0 && ends.peek() <= s) ends.pop(); ends.push(e); } return ends.size();}Editorial#
Identical structure to Meeting Rooms II — “machines” and “rooms” are interchangeable resources for non-overlapping interval scheduling. The heap’s size is the peak concurrency, which is the answer.
Complexity#
- Time: O(n log n).
- Space: O(n).
Concept revision#
Related#