Given an array of numbers and a number ‘k’, find the median of all the ‘k’ sized sub-arrays (or windows) of the array.
Input: nums=[1, 2, -1, 3, 5], k = 2
Output: [1.5, 0.5, 1.0, 4.0]
Explanation: Lets consider all windows of size ‘2’:
[1, 2, -1, 3, 5] -> median is 1.5
[1, 2, -1, 3, 5] -> median is 0.5
[1, 2, -1, 3, 5] -> median is 1.0
[1, 2, -1, 3, 5] -> median is 4.0
public double[] medianSlidingWindow(int[] nums, int k) {
final PriorityQueue<Integer> minHeap = new PriorityQueue<>();
final PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
double[] result = new double[nums.length - k + 1];
for (int i = 0; i < k; i++) {
addToHeaps(minHeap, maxHeap, nums[i]);
}
int start = 0, end = k - 1;
while (end < nums.length) {
if (maxHeap.size() > minHeap.size()) {
result[start] = maxHeap.peek();
} else {
result[start] = (maxHeap.peek() + minHeap.peek()) / 2.0;
}
end++;
if (end == nums.length) {
return result;
}
int toRemove = nums[start];
if (toRemove <= maxHeap.peek()) {
maxHeap.remove(toRemove);
} else {
minHeap.remove(toRemove);
}
rebalanceHeaps(minHeap, maxHeap);
start++;
addToHeaps(minHeap, maxHeap, nums[end]);
}
return result;
}
void addToHeaps(PriorityQueue<Integer> minHeap, PriorityQueue<Integer> maxHeap, int val) {
if (maxHeap.isEmpty() || maxHeap.peek() >= val) {
maxHeap.add(val);
} else {
minHeap.add(val);
}
rebalanceHeaps(minHeap, maxHeap);
}
private void rebalanceHeaps(PriorityQueue<Integer> minHeap, PriorityQueue<Integer> maxHeap) {
if (maxHeap.size() > minHeap.size() + 1) {
minHeap.add(maxHeap.poll());
} else if (minHeap.size() > maxHeap.size()) {
maxHeap.add(minHeap.poll());
}
}
The time complexity of our algorithm is O(N*K)
where ‘N’ is the total number of elements in the input array and ‘K’ is the size of the sliding window. This is due to the fact that we are going through all the ‘N’ numbers and, while doing so, we are doing two things:
O(K) for storing elements in heaps
two heaps, first half for maxHeap, second for minHeap