Skip to main content

Sliding Window Median

Problem

The median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle values.

  • For examples, if arr = [2,3,4], the median is 3.
  • For examples, if arr = [1,2,3,4], the median is (2 + 3) / 2 = 2.5.

You are given an integer array nums and an integer k. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

Return the median array for each window in the original array. Answers within 10-5 of the actual value will be accepted.

 

Example 1:

Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [1.00000,-1.00000,-1.00000,3.00000,5.00000,6.00000]
Explanation: 
Window position                Median
---------------                -----
[1  3  -1] -3  5  3  6  7        1
 1 [3  -1  -3] 5  3  6  7       -1
 1  3 [-1  -3  5] 3  6  7       -1
 1  3  -1 [-3  5  3] 6  7        3
 1  3  -1  -3 [5  3  6] 7        5
 1  3  -1  -3  5 [3  6  7]       6

Example 2:

Input: nums = [1,2,3,4,2,3,1,4,2], k = 3
Output: [2.00000,3.00000,3.00000,3.00000,2.00000,3.00000,2.00000]

 

Constraints:

  • 1 <= k <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1

Solution

/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var medianSlidingWindow = function(nums, k) {
const window = Array(k)
.fill(null)
.map((_, i) => nums[i])
.sort((a, b) => a - b);
const res = [median(window)];

for (let i = 1; i <= nums.length - k; i++) {
window.splice(window.indexOf(nums[i - 1]), 1);
insort(window, nums[i + k - 1]);
res.push(median(window));
}
return res;
};

// find median of arr
var median = function(arr) {
const len = arr.length - 1;
if (arr % 2) { // odd length
return arr[len >> 1];
} else { // even length
return (arr[len >> 1] + arr[(len + 1) >> 1]) / 2;
}
};

// insert val into sorted array arr
var insort = function(arr, val) {
const i = arr.findIndex(el => el > val);
if (i === 0) {
arr.unshift(val);
} else if (i === -1) {
arr.push(val);
} else {
arr.splice(i, 0, val);
}
};

Initially, we put nums[0:k] into window and sort it. As our window slides across nums, we remove the first element of the previous window from window, and insert the next element into window at its sorted position. Since window is sorted, the median is simply the mean of the centre element(s).

Note that this solution has runtime O(kn) which is suboptimal. There exists more optimized solutions with runtime O(nlogk). However, those solutions require more advanced data structures like TreeSet (Java), multiset (C++), or some form of self balancing BST, which Javascript does not have.