Method 1.1 Two Heap with Lazy Deletion
There are usually two methods to do the lazy deletion:
use a map
use a
Summary
As we can see in the previous version, the delete function is very time-consuming. Lazy deletion can be used to improve performance.
The basic idea is that:
when an element is supposed to be removed, we do not actually remove it from the heap immediately.
Instead, we keep track of the elements to be deleted in a hash table. When an element at the top of the heap is supposed to be deleted, we then remove it.
Here is the code:
class Solution {
private int windowSize;
private PriorityQueue<Integer> larger;
private PriorityQueue<Integer> smaller;
private HashMap<Integer, Integer> delayedRemovals; // not hash set since it might have same element
private int smallerDelSize;
private int largerDelSize;
public double[] medianSlidingWindow(int[] nums, int k) {
this.windowSize = k;
this.smaller = new PriorityQueue<>(Collections.reverseOrder());
this.larger = new PriorityQueue<>();
this.delayedRemovals = new HashMap<>();
double[] result = new double[nums.length - k + 1];
for (int i = 0; i < nums.length; i++) {
if (i >= k) { // delete start (k + 1)th, delete (i - k)th
this.delete(nums[i - k]);
}
this.insert(nums[i]); // insert start 0th
if (i >= k -1) { // record result start kth
result[i - k + 1] = this.findMedian();
}
}
return result;
}
private void insert(int num) {
if (this.smaller.isEmpty() || num <= this.smaller.peek()) {
this.smaller.offer(num);
}
else {
this.larger.offer(num);
}
rebalance();
}
private void delete(int num){
delayedRemovals.put(num, delayedRemovals.getOrDefault(num, 0) + 1);
if (this.smaller.peek() >= num){
this.smallerDelSize++;
}
else {
this.largerDelSize ++;
}
while (!this.smaller.isEmpty() && delayedRemovals.containsKey(this.smaller.peek())) {
delayedRemovals.put(smaller.peek(), delayedRemovals.get(this.smaller.peek()) - 1);
if (delayedRemovals.get(this.smaller.peek()) == 0) {
delayedRemovals.remove(this.smaller.peek());
}
this.smaller.poll();
this.smallerDelSize--;
}
while (!this.larger.isEmpty() && delayedRemovals.containsKey(this.larger.peek())) {
delayedRemovals.put(this.larger.peek(), delayedRemovals.get(this.larger.peek()) - 1);
if (delayedRemovals.get(this.larger.peek()) == 0) {
delayedRemovals.remove(this.larger.peek());
}
this.larger.poll();
this.largerDelSize--;
}
rebalance();
}
private double findMedian() {
if (this.smaller.size() == this.larger.size()) {
return (double) this.smaller.peek() + this.larger.peek() /2.0;
}
else {
return (double) this.smaller.peek();
}
}
private void rebalance() {
int smallerSize = this.smaller.size() - this.smallerDelSize;
int largerSize = this.larger.size() - this.largerDelSize;
int size = smallerSize + largerSize;
if (size % 2 == 0) {
while (smallerSize != largerSize) {
if (smallerSize > largerSize) {
this.larger.offer(this.smaller.poll());
}
else {
this.smaller.offer(this.larger.poll());
}
}
}
else {
while (smallerSize!= this.larger.size() + 1){
if (smallerSize > this.larger.size()) {
this.larger.offer(this.smaller.poll());
}
else {
this.smaller.offer(this.larger.poll());
}
}
}
}
}
Last updated