Comprehensive theory, algorithmic patterns, templates, and problem catalog for Heaps and Priority Queues.
A Binary Heap is a complete binary tree satisfying the heap property:
-
Max-Heap: Parent value
$\ge$ children values. Root is the maximum. -
Min-Heap: Parent value
$\le$ children values. Root is the minimum.
- Insertion (
push):$\mathcal{O}(\log N)$ via heapify up (sift up). - Extraction (
pop):$\mathcal{O}(\log N)$ via heapify down (sift down). - Peek Top (
top):$\mathcal{O}(1)$ . - Building Heap from Array (
std::make_heap):$\mathcal{O}(N)$ .
std::priority_queue<T>: Defaults to Max-Heap.std::priority_queue<T, vector<T>, greater<T>>: Min-Heap.- Custom comparator with structs or lambda expressions.
Maintain a min-heap of size
#include <queue>
// Kth Largest Element in an Array
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int>> minHeap;
for (int num : nums) {
minHeap.push(num);
if (static_cast<int>(minHeap.size()) > k) {
minHeap.pop(); // Remove smallest element
}
}
return minHeap.top();
}class MedianFinder {
private:
priority_queue<int> maxHeap; // Lower half
priority_queue<int, vector<int>, greater<int>> minHeap; // Upper half
public:
void addNum(int num) {
maxHeap.push(num);
minHeap.push(maxHeap.top());
maxHeap.pop();
if (maxHeap.size() < minHeap.size()) {
maxHeap.push(minHeap.top());
minHeap.pop();
}
}
double findMedian() {
if (maxHeap.size() > minHeap.size()) {
return maxHeap.top();
}
return (maxHeap.top() + minHeap.top()) / 2.0;
}
};struct Compare {
bool operator()(const ListNode* a, const ListNode* b) {
return a->val > b->val; // Min-heap
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*, vector<ListNode*>, Compare> pq;
for (ListNode* head : lists) {
if (head) pq.push(head);
}
ListNode dummy(0);
ListNode* curr = &dummy;
while (!pq.empty()) {
ListNode* smallest = pq.top();
pq.pop();
curr->next = smallest;
curr = curr->next;
if (smallest->next) pq.push(smallest->next);
}
return dummy.next;
}When extracting top-K elements across multidimensional structures with monotonic properties (e.g. subarray range differences):
- Precompute
$\mathcal{O}(1)$ Range Queries (Sparse Table for min/max). - Exploit monotonicity: for fixed
$l$ ,$V(l, r)$ is non-decreasing with$r \implies$ optimal right bound starts at$r = n - 1$ . - Seed Max-Heap with
$(V(l, n - 1), l, n - 1)$ for all$l \in [0, n - 1]$ . - Greedily pop top element, accumulate, and push
$(V(l, r - 1), l, r - 1)$ in$\mathcal{O}(\log N)$ .
When computing the continuous upper envelope / contour of overlapping intervals with heights:
- Deconstruct each rectangle
$[L, R, H]$ into two signed boundary events:(L, -H)(enter) and(R, +H)(leave). - Sort events with
std::pair<int, int>$(x, h)$ to naturally prioritize higher starts and process starts before ends at identical$x$ . - Maintain active heights in an ordered
std::multiset<int> active = {0}(or max-heap with delayed deletion). - Emit key points
$[x, \max(\text{active})]$ whenever the maximum active height strictly changes.
When determining the bounding envelope / bottleneck water level across escape paths in a 2D terrain:
-
Perimeter Initialization: Push all
$2(m + n) - 4$ perimeter boundary cells$(h, r, c)$ into a Min-Heap and mark them visited. -
Min-Heap Extraction: Pop the lowest active boundary cell
$(h, r, c)$ . This cell is guaranteed to be the lowest escape spillway for its unvisited interior neighbors. -
Neighbor Evaluation & Effective Height Propagation:
- For each unvisited neighbor
$(nr, nc)$ , trapped water volume is$\max(0, h - \text{heightMap}[nr][nc])$ . - Push
$(nr, nc)$ into the Min-Heap with updated effective boundary height$\max(h, \text{heightMap}[nr][nc])$ .
- For each unvisited neighbor
- Solves 2D minimax bottleneck path problems in
$\mathcal{O}(M \cdot N \log(M \cdot N))$ time with$\mathcal{O}(M \cdot N)$ space.
-
Min-Heap Comparator Inversion: In
std::priority_queue,std::greater<T>produces a min-heap (contrary tostd::sortwheregreaterproduces descending order). -
Empty Heap Access: Calling
.top()or.pop()on an emptypriority_queuecauses undefined behavior / crash. -
Floating Point Division in Median: Always cast sums to
doublebefore dividing by2.0. -
Total Sum Overflow: Summing
$K$ values each up to$10^9$ requireslong longfor accumulators.
| # | Title | Difficulty | Time | Space | Solution Link |
|---|---|---|---|---|---|
| 23 | Merge k Sorted Lists | Hard |
C++ | ||
| 218 | The Skyline Problem | Hard |
C++ | ||
| 295 | Find Median from Data Stream | Hard |
C++ | ||
| 407 | Trapping Rain Water II | Hard |
C++ | ||
| 502 | IPO | Hard |
C++ | ||
| 630 | Course Schedule III | Hard |
C++ | ||
| 632 | Smallest Range Covering Elements from K Lists | Hard |
C++ | ||
| 778 | Swim in Rising Water | Hard |
C++ | ||
| 857 | Minimum Cost to Hire K Workers | Hard |
C++ | ||
| 3691 | Maximum Total Subarray Value II | Hard |
C++ |