Given an integer array nums
and an integer k
, you are tasked with finding the median of each sliding window of size k
as it moves from the beginning to the end of the array. The median is defined as the middle value in an ordered list of integers. If the list has an even number of elements, the median is the average of the two middle values.
Example:
Consider the array nums = [1, 3, -1, -3, 5, 3, 6, 7]
and a window size of k = 3
. The sliding window moves as follows:
[1, 3, -1], -3, 5, 3, 6, 7
(Median: 1)1, [3, -1, -3], 5, 3, 6, 7
(Median: -1)1, 3, [-1, -3, 5], 3, 6, 7
(Median: -1)1, 3, -1, [-3, 5, 3], 6, 7
(Median: 3)1, 3, -1, -3, [5, 3, 6], 7
(Median: 5)1, 3, -1, -3, 5, [3, 6, 7]
(Median: 6)Therefore, the output should be [1, -1, -1, 3, 5, 6]
. Note that in a real coding problem floating-point values may be expected.
Task:
Write a function that takes an integer array nums
and an integer k
as input, and returns an array containing the medians of each sliding window.
Constraints:
1 <= k <= nums.length <= 10^5
-2^31 <= nums[i] <= 2^31 - 1
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We're trying to find the middle number in a sliding group of numbers. The most basic way to do this is to look at every possible group of numbers in the larger list. For each group, we find the middle number by sorting it and picking the element in the middle.
Here's how the algorithm would work step-by-step:
def sliding_window_median_brute_force(numbers, window_size):
median_list = []
# Iterate through the array, creating each window
for i in range(len(numbers) - window_size + 1):
window = numbers[i:i + window_size]
# Sort the window to easily find the median.
sorted_window = sorted(window)
# Determine if window size is even or odd
if window_size % 2 == 0:
median = (sorted_window[window_size // 2 - 1] + sorted_window[window_size // 2]) / 2
else:
# Index for middle of list is different for odd and even
median = sorted_window[window_size // 2]
median_list.append(median)
return median_list
To efficiently find the median within a moving window, we use two balanced data structures to keep track of the smaller and larger halves of the numbers within the window. As the window slides, we maintain the balance and quickly identify the median without re-sorting every time.
Here's how the algorithm would work step-by-step:
from sortedcontainers import SortedList
def sliding_window_median(numbers, window_size):
result = []
smaller_half = SortedList()
larger_half = SortedList()
for i in range(len(numbers)):
# Remove the leftmost element if the window is full.
if i >= window_size:
element_to_remove = numbers[i - window_size]
if element_to_remove in smaller_half:
smaller_half.remove(element_to_remove)
else:
larger_half.remove(element_to_remove)
# Add the current element to the appropriate half.
if not smaller_half or numbers[i] <= smaller_half[-1]:
smaller_half.add(numbers[i])
else:
larger_half.add(numbers[i])
# Rebalance the two halves.
while len(smaller_half) > len(larger_half) + (window_size % 2):
larger_half.add(smaller_half.pop())
while len(larger_half) > len(smaller_half):
# Maintain balance between the two sets.
smaller_half.add(larger_half.pop(0))
if i >= window_size - 1:
# Calculate the median for the current window.
if window_size % 2 == 0:
median = (smaller_half[-1] + larger_half[0]) / 2.0
else:
median = smaller_half[-1]
result.append(median)
return result
Case | How to Handle |
---|---|
Empty input array (nums is null or has length 0) | Return an empty array immediately since there are no windows to process. |
k is zero or negative | Throw an IllegalArgumentException because a window size must be positive. |
k is greater than the length of nums | Return an empty array or an array with a single median equal to the median of the entire nums array if k > nums.length. |
nums contains only one element and k is 1 | Return an array containing the single element as the median. |
Large input array size with a large k, potentially leading to performance issues | Use efficient data structures like ordered sets (e.g., TreeSet or Priority Queues) to maintain the sliding window, ensuring logarithmic time complexity for insertion, deletion, and median retrieval. |
nums contains duplicate values within a window | The ordered set/priority queue based solution correctly handles duplicates as each instance is treated individually. |
nums contains negative numbers or extreme boundary values (Integer.MIN_VALUE, Integer.MAX_VALUE) | The solution using comparators in ordered sets or priority queues correctly handles negative numbers and extreme values without integer overflow issues during comparisons. |
Input array with integer values very close to each other (e.g., with floating-point precision issues if dividing for the median) | Avoid explicit division when k is even, instead take the average of the two middle elements to prevent potential floating point errors; use double to represent medians. |