困難題是真的困難
1.首先假設接受了這個想法:維護一個排序好的最大值列表,每次右移彈出所有,比新加入陣列小的數字。、
我自己寫下來的疑問是:
如果右移,需要判斷左邊移除的數字是否是已經儲存的內容,如果有,需要pop。我的想法就是遍歷尋找,因為也不知道這個數字的位置啊,移除的元素也不一定是最大值,不能每次都移除最大值。
需要判斷右邊進來的數字,彈出所有比他小的內容。是怎麼樣簡潔做到這兩點的?每次就算遍歷一遍也很慢。
2.接下來分析題解的觀點
儲存的不是數字,是索引。
小疑問:不還是要判斷這兩點嗎?
分析一下題解程式碼:
1 from collections import deque 2 3 class Solution: 4 def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]: 5 q = deque() 6 max_list = [] 7 8 for i, num in enumerate(nums): 9 # Remove indices that are out of the current window 10 while q and q[0] < i - k + 1: 11 q.popleft() 12 13 # Remove indices whose corresponding values are less than the current number 14 while q and nums[q[-1]] < num: 15 q.pop() 16 17 # Add the current index to the deque 18 q.append(i) 19 20 # If our window has hit size k, append the current max to the output list 21 if i >= k - 1: 22 max_list.append(nums[q[0]]) 23 24 return max_list
解答一下之前的疑惑:
如果儲存的是數字,便不能有自動排序的這個功能了(index從小到大一次排列)。當右移的時候,如果儲存的是index,因為新增最大值進來的時候,總是從右邊新增,左index恆小於右index。所以刪除元素的時候,會更加方便。直接判斷最左邊這個是不是小於i-k+1就可以了。可以減少去尋找這個值的麻煩。
右邊這點,尋找的過程也是一樣的,需要一直遍歷,沒啥好說的。最重要的思想,自己沒有想到的是,刪除左端元素,使用索引會不需要進行遍歷,直接pop最左邊的就行。我覺得每次其實也只需要看看是不是要pop(0),因為只用移除一個元素。修改一版,確實是可以的(忽略一開始想的分段處理,分段也是OK的):
class Solution: def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]: max_list = [] q = [] for i in range(len(nums)): # if i < k: # while q and q[0] < i-k+1: # q.pop(0) # while q and nums[q[-1]] < nums[i]: # q.pop() # q.append(i) # if i == k-1: # max_list.append(nums[q[0]]) # else: if q and q[0] == i-k: q.pop(0) while q and nums[q[-1]] < nums[i]: q.pop() q.append(i) if i>k-2: max_list.append(nums[q[0]]) return max_list
所以其實不是自己不理解,是沒有對索引有深刻的認知。其實思路是正確的,實現起來也很樸素。就是需要自己消化一下。