- Choose the invariant that makes a window valid or useful.
- Advance the right boundary and add the new element.
- Move the left boundary only as needed while maintaining the invariant and updating the answer.
Code notes
- 114 lines of Python from the credited upstream file sliding-window-median.py.
- The implementation visibly relies on sequence storage, hash lookup, work queue.
- No explicit loop blocks detected.
Complexity
Confirm that neither pointer moves backwards; if so, the scan is usually linear apart from the window’s data-structure operations.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
123 4from sortedcontainers import SortedList5 6 7class Solution(object):8 def medianSlidingWindow(self, nums, k):9 """10 :type nums: List[int]11 :type k: int12 :rtype: List[float]13 """14 sl = SortedList(float(nums[i])for i in xrange(k))15 result = [(sl[k2]+sl[k2-(1-k%2)])/2]16 for i in xrange(k, len(nums)):17 sl.add(float(nums[i]))18 sl.remove(nums[i-k])19 result.append((sl[k2]+sl[k2-(1-k%2)])/2)20 return result21 22 232425import collections26import heapq27 28 29class Solution2(object):30 def medianSlidingWindow(self, nums, k):31 """32 :type nums: List[int]33 :type k: int34 :rtype: List[float]35 """36 def lazy_delete(heap, to_remove, sign):37 while heap and sign*heap[0] in to_remove:38 to_remove[sign*heap[0]] -= 139 if not to_remove[sign*heap[0]]:40 del to_remove[sign*heap[0]]41 heapq.heappop(heap)42 43 def full_delete(heap, to_remove, sign): 44 result = []45 for x in heap:46 if sign*x not in to_remove:47 result.append(x)48 continue49 to_remove[sign*x] -= 150 if not to_remove[sign*x]:51 del to_remove[sign*x]52 heap[:] = result53 heapq.heapify(heap)54 55 min_heap, max_heap = [], []56 for i in xrange(k):57 if i%2 == 0:58 heapq.heappush(min_heap, -heapq.heappushpop(max_heap, -nums[i]))59 else:60 heapq.heappush(max_heap, -heapq.heappushpop(min_heap, nums[i]))61 result = [float(min_heap[0])] if k%2 else [(min_heap[0]-max_heap[0])/2.0]62 to_remove = collections.defaultdict(int)63 for i in xrange(k, len(nums)):64 heapq.heappush(max_heap, -heapq.heappushpop(min_heap, nums[i]))65 if nums[i-k] > -max_heap[0]:66 heapq.heappush(min_heap, -heapq.heappop(max_heap))67 to_remove[nums[i-k]] += 168 lazy_delete(max_heap, to_remove, -1)69 lazy_delete(min_heap, to_remove, 1)70 if len(min_heap)+len(max_heap) > 2*k:71 full_delete(max_heap, to_remove, -1)72 full_delete(min_heap, to_remove, 1)73 result.append(float(min_heap[0]) if k%2 else (min_heap[0]-max_heap[0])/2.0)74 return result75 76 777879import collections80import heapq81 82 83class Solution3(object):84 def medianSlidingWindow(self, nums, k):85 """86 :type nums: List[int]87 :type k: int88 :rtype: List[float]89 """90 def lazy_delete(heap, to_remove, sign):91 while heap and sign*heap[0] in to_remove:92 to_remove[sign*heap[0]] -= 193 if not to_remove[sign*heap[0]]:94 del to_remove[sign*heap[0]]95 heapq.heappop(heap)96 97 min_heap, max_heap = [], []98 for i in xrange(k):99 if i%2 == 0:100 heapq.heappush(min_heap, -heapq.heappushpop(max_heap, -nums[i]))101 else:102 heapq.heappush(max_heap, -heapq.heappushpop(min_heap, nums[i]))103 result = [float(min_heap[0])] if k%2 else [(min_heap[0]-max_heap[0])/2.0]104 to_remove = collections.defaultdict(int)105 for i in xrange(k, len(nums)):106 heapq.heappush(max_heap, -heapq.heappushpop(min_heap, nums[i]))107 if nums[i-k] > -max_heap[0]:108 heapq.heappush(min_heap, -heapq.heappop(max_heap))109 to_remove[nums[i-k]] += 1110 lazy_delete(max_heap, to_remove, -1)111 lazy_delete(min_heap, to_remove, 1)112 result.append(float(min_heap[0]) if k%2 else (min_heap[0]-max_heap[0])/2.0)113 return result114