Files

66 lines
1.9 KiB
Python

"""Sliding window maximum (LeetCode 239).
Returns the maximum of each contiguous window of size `k` over `nums`
in O(n) time using a monotonic deque of indices.
Subtle points handled:
- empty input / k <= 0 -> []
- k == 1 -> nums copy
- k >= len(nums) -> [max(nums)] (or [] if empty)
- duplicate values (deque keeps indices, not values, to handle expiry)
- negative numbers
"""
from collections import deque
from typing import List
def sliding_window_max(nums: List[int], k: int) -> List[int]:
if not nums or k <= 0:
return []
if k == 1:
return list(nums)
n = len(nums)
if k >= n:
return [max(nums)]
dq = deque() # indices, nums[dq[0]] is current max; values strictly decreasing
out: List[int] = []
for i, x in enumerate(nums):
# evict indices outside window
while dq and dq[0] <= i - k:
dq.popleft()
# maintain decreasing values
while dq and nums[dq[-1]] <= x:
dq.pop()
dq.append(i)
if i >= k - 1:
out.append(nums[dq[0]])
return out
def _brute(nums, k):
if not nums or k <= 0:
return []
return [max(nums[i:i + k]) for i in range(len(nums) - k + 1)]
if __name__ == "__main__":
import random
rng = random.Random(123)
for _ in range(5000):
n = rng.randint(0, 40)
nums = [rng.randint(-20, 20) for _ in range(n)]
k = rng.randint(0, n + 3) if n else rng.randint(0, 5)
got = sliding_window_max(nums, k)
# compute expected via brute respecting edge rules
if not nums or k <= 0:
exp = []
elif k == 1:
exp = list(nums)
elif k >= len(nums):
exp = [max(nums)]
else:
exp = [max(nums[i:i + k]) for i in range(len(nums) - k + 1)]
assert got == exp, (nums, k, got, exp)
print("self-check: 5000 random cases passed")