02
Sliding median (Two Heaps Sub-pattern)
Running median plus removals: as the window slides, one number enters and one leaves.
Signals in the problem statement
- ›
"median of each window of size k"
What makes it different
The only new part is removing the leaving number. Heaps can't do that directly, so use lazy deletion (a delayed count map, pruned when a stale number reaches a top) or replace both heaps with two multisets. Values reach ±2³¹ − 1, so average them as doubles.
Questions
ordered from “learn the idea” to “recognise it without help”- 1Sliding Window MedianWalkthroughHardInterview-Level·LeetCode #480
Template
sliding-median-template.cpp
// Sliding window median with two heaps and lazy deletion.
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
priority_queue<int> low; // smaller half
priority_queue<int, vector<int>, greater<int>> high; // larger half
unordered_map<int, int> delayed; // value -> copies waiting to be removed
int lowSize = 0, highSize = 0; // LIVE counts only
auto prune = [&](auto& h) { // drop stale tops
while (!h.empty() && delayed.count(h.top())) {
if (--delayed[h.top()] == 0) delayed.erase(h.top());
h.pop();
}
};
auto rebalance = [&]() { // low has the same size or one more
if (lowSize > highSize + 1) {
high.push(low.top()); low.pop(); lowSize--; highSize++; prune(low);
} else if (lowSize < highSize) {
low.push(high.top()); high.pop(); highSize--; lowSize++; prune(high);
}
};
vector<double> res;
for (int i = 0; i < (int)nums.size(); i++) {
int x = nums[i];
if (low.empty() || x <= low.top()) { low.push(x); lowSize++; }
else { high.push(x); highSize++; }
if (i >= k) { // nums[i-k] leaves the window
int gone = nums[i - k];
delayed[gone]++;
if (gone <= low.top()) { lowSize--; if (gone == low.top()) prune(low); }
else { highSize--; if (gone == high.top()) prune(high); }
}
rebalance();
if (i >= k - 1)
res.push_back(k % 2 ? (double)low.top() : ((double)low.top() + high.top()) / 2.0);
}
return res;
}Remember this · Two Heaps
Trigger
Running median, sliding median, choosing from two pools (available vs locked).
Think
Can I split the data into two halves and only care about the boundary between them?
Key question
How do I rebalance so the sizes differ by at most one?