Problem¶
You are given an array of integers nums, 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 max sliding window.
Example 1:
Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [3,3,5,5,6,7]
Explanation:
Window position Max
--------------- -----
[1 3 -1] -3 5 3 6 7 **3**
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 **5**
1 3 -1 -3 [5 3 6] 7 **6**
1 3 -1 -3 5 [3 6 7] **7**
Example 2:
Input: nums = [1], k = 1
Output: [1]
Constraints:
1 <= nums.length <= 105-10**4 <= nums[i] <= 10**41 <= k <= nums.length
Solve¶
Re-run sum every time¶
This is a TLE solution
There isn’t much thing to said, still I try to do some thing cleaver:
- We use a circle to store the current sliding window
- The max function O(k) is call only if the added number is smaller than replace value and replace value is our current maximum number
| Time Submitted | Status | Runtime | Memory | Language |
|---|---|---|---|---|
| 08/16/2023 18:17 | Time Limit Exceeded | N/A | N/A | python3 |
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
circle = nums[:k]
currMax = max(circle)
res = [currMax]
index = 0
rerun = False
for v in nums[k:]:
if circle[index] == currMax:
rerun = True
if v >= currMax:
rerun = False
currMax = v
circle[index] = v
if rerun:
rerun = False
currMax = max(circle)
res.append(currMax)
index += 1
index %= k
return res
Min-max tree¶
A good close to O(log n) time complexity to find any Maximum number in any range. The process is that we build and storing divide by 2 of the array maximum
We then travel through and comparing all node that covering [x, y] range
| Time Submitted | Status | Runtime | Memory | Language |
|---|---|---|---|---|
| 08/16/2023 23:24 | Accepted | 8451 ms | 352 MB | python3 |
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
cache = {}
# inclusive
def buildCache(l, r):
if l == r:
cache[(l,r)] = nums[l]
else:
m = (l + r) // 2
buildCache(l, m)
buildCache(m+1, r)
cache[(l,r)] = max(cache[(l,m)], cache[(m+1,r)])
buildCache(0, len(nums) - 1)
def getCache(x, y, l=0, r=len(nums)-1):
if (y < l) or (r < x):
return -100000
if (x <= l <= r <= y):
return cache[(l,r)]
m = (l + r) // 2
return max(getCache(x,y, l,m), getCache(x,y, m+1,r))
res = []
for i in range(len(nums)-k+1):
res.append(getCache(i, i+k-1))
return res
Priority Queue with random access update¶
Another good close to O(log n) time complexity that creating a Heap to easily find Maximum number.
The process is that we build a modified heap with a replace that can access the last insert number and replace it with the next number, base on:
- A cycle, fixed size
array, that use to mimic the current sliding window. In the implement already remove that. - A heap
self.heap - Array
possitionthat indexistore the position ofheapelementiinarray. Orarray[i] == heap[pos[i]] - Array
revertPossitionthat indexistore the position ofarrayelementiin theheap. Orarray[revPos[i]] == heap[i]
Example:
index [1, 2, 3, 4, 5, 6, 7, 8]
---
nums [1, 9, 8, 4, 4, 3, 2, 5, 1, 3 , ...
array [1, 9, 8, 4, 4, 3, 2, 5]
heap [9, 5, 8, 4, 4, 3, 2, 1]
pos [2, 8, 3, 4, 5, 6, 7, 1]
revPos [8, 1, 3, 4, 5, 6, 7, 2]
Explain:
- Element
9have position1in theheap, but have the position2in the array; So itspossitionis2 - Element
1have position1in thearray, but have the position1in the array; So itsrevertPossitionis8
So, when we update our sliding window array. We remove the last insert next element of cycle, fixed size array, change it to new value v of the next number in nums array. While doing so, we update:
heap: Replacingheap[revPos[next]]with new valuev- We then update the
heapbase onvvalue (go up or down in the heap). We also keep track ofposandrevPoschange by swapping them correspond withheapelement position change:swap(pos[parrent], pos[child]): Basic swapingswap(revertPos[ pos[child] ], self.revertPos[ pos[parrent] ]): Advantage swap, took me too long when trying to done therevertPosarray directly (noposarray). After lot of trial and error, I have to go back to this implementation for simplicity.
It took quite some time to reimplement heap, quite great that I can done it.
The Heap data structure is implement base on array. To reduce the complexity of the calculation I use array [1..n] by padding all of my array with element [0] (as array in python start at 0)
Start at node x in the heap, we can access
- To get parent node:
x//2(if x != 1) - To get child node:
x*2,x*2 + 1(if them inside the heap)
The heap have fixed size, and the update is change directly on one of heap node, so we only implement up, down function to update the element position after change.
The main component is keep track of next element that need to replace. The array is cycle, with index [1..n] (inclusive), so next is increase by one or restart to 1 at next == n+1 every loop
from typing import List
class Heap:
def getChild(self, x):
res = []
if x*2+1 <= self.size:
res.append(x*2+1)
if x*2 <= self.size:
res.append(x*2)
return res
def getParrent(x):
return x // 2
def __init__(self, arr):
self.heap = [-1] + arr
self.size = len(arr)
self.pos = list(range(self.size + 1))
self.revertPos = list(range(self.size + 1))
self.next = 1
for i in range(1, self.size+1):
self.update(i)
for i in range(1, self.size+1):
self.revertPos[self.pos[i]] = i
def update(self, x):
if x == 1:
return
px = Heap.getParrent(x)
if self.heap[x] > self.heap[px]:
self.heap[x], self.heap[px] = self.heap[px], self.heap[x]
self.pos[x], self.pos[px] = self.pos[px], self.pos[x]
self.revertPos[self.pos[x]], self.revertPos[self.pos[px]
] = self.revertPos[self.pos[px]], self.revertPos[self.pos[x]]
self.update(px)
def downgrade(self, x):
cx_arr = self.getChild(x)
if len(cx_arr) == 2 and self.heap[cx_arr[1]] > self.heap[cx_arr[0]]:
cx_arr.pop(0)
for cx in cx_arr:
if self.heap[x] < self.heap[cx]:
self.heap[x], self.heap[cx] = self.heap[cx], self.heap[x]
self.pos[x], self.pos[cx] = self.pos[cx], self.pos[x]
self.revertPos[self.pos[x]], self.revertPos[self.pos[cx]
] = self.revertPos[self.pos[cx]], self.revertPos[self.pos[x]]
self.downgrade(cx)
break
def incNext(self):
if self.next >= self.size:
self.next = 1
else:
self.next += 1
def replace(self, v):
pos = self.revertPos[self.next]
self.incNext()
old = self.heap[pos]
self.heap[pos] = v
if old < v:
self.update(pos)
else:
self.downgrade(pos)
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
heap = Heap(nums[:k])
res = [heap.heap[1]]
for i in nums[k:]:
heap.replace(i)
res.append(heap.heap[1])
return res
Created : August 16, 2023