Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Finding median for every window in JavaScript
In mathematics, the median is the middle value in an ordered (sorted) list of numbers. If the list has an even number of elements, the median is the average of the two middle values.
Problem Statement
We need to write a JavaScript function that takes an array of integers and a window size, then calculates the median for each sliding window of that size. The function returns an array containing all the calculated medians.
For example, given:
const arr = [5, 3, 7, 5, 3, 1, 8, 9, 2, 4, 6, 8]; const windowSize = 3;
The expected output is:
[5, 5, 5, 3, 3, 8, 8, 4, 4, 6]
Window Analysis
Here's how each window produces its median:
| Index | Window | Sorted Window | Median |
|---|---|---|---|
| 0 | [5, 3, 7] | [3, 5, 7] | 5 |
| 1 | [3, 7, 5] | [3, 5, 7] | 5 |
| 2 | [7, 5, 3] | [3, 5, 7] | 5 |
| 3 | [5, 3, 1] | [1, 3, 5] | 3 |
| 4 | [3, 1, 8] | [1, 3, 8] | 3 |
| 5 | [1, 8, 9] | [1, 8, 9] | 8 |
Solution Using Binary Search
The most efficient approach uses binary search to maintain a sorted window as we slide through the array:
const binarySearch = (arr, target, left, right) => {
while (left < right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
};
const medianSlidingWindow = (arr, windowSize) => {
if (windowSize > arr.length) return [];
let left = 0;
let right = windowSize - 1;
const result = [];
// Initialize the first window and sort it
const window = arr.slice(0, windowSize);
window.sort((a, b) => a - b);
while (right < arr.length) {
// Calculate median for current window
const median = windowSize % 2 === 0
? (window[Math.floor(windowSize / 2) - 1] + window[Math.floor(windowSize / 2)]) / 2
: window[Math.floor(windowSize / 2)];
result.push(median);
// Move window if not at the end
if (right + 1 < arr.length) {
// Remove the leftmost element
const removeElement = arr[left];
const removeIndex = binarySearch(window, removeElement, 0, window.length);
window.splice(removeIndex, 1);
// Add the new rightmost element
const addElement = arr[right + 1];
const insertIndex = binarySearch(window, addElement, 0, window.length);
window.splice(insertIndex, 0, addElement);
left++;
right++;
} else {
break;
}
}
return result;
};
// Test the function
const arr = [5, 3, 7, 5, 3, 1, 8, 9, 2, 4, 6, 8];
const windowSize = 3;
console.log(medianSlidingWindow(arr, windowSize));
[5, 5, 5, 3, 3, 8, 8, 4, 4, 6]
How It Works
The algorithm maintains a sorted window and uses binary search for efficient insertions and deletions:
- Initialize: Create the first window and sort it
- Calculate median: Find middle element(s) based on window size
- Slide window: Remove leftmost element and add new rightmost element
- Maintain order: Use binary search to find correct positions for insertion/deletion
Alternative Simple Approach
For smaller datasets, a simpler approach sorts each window individually:
const medianSlidingWindowSimple = (arr, windowSize) => {
const result = [];
for (let i = 0; i <= arr.length - windowSize; i++) {
const window = arr.slice(i, i + windowSize);
window.sort((a, b) => a - b);
const median = windowSize % 2 === 0
? (window[windowSize / 2 - 1] + window[windowSize / 2]) / 2
: window[Math.floor(windowSize / 2)];
result.push(median);
}
return result;
};
console.log(medianSlidingWindowSimple([5, 3, 7, 5, 3, 1, 8, 9, 2, 4, 6, 8], 3));
[5, 5, 5, 3, 3, 8, 8, 4, 4, 6]
Conclusion
The binary search approach efficiently maintains sorted order while sliding the window, providing O(n log k) complexity where n is array length and k is window size. For smaller datasets, the simple sorting approach offers better readability with O(nk log k) complexity.
