1. 程式人生 > 實用技巧 >362. 滑動視窗的最大值(單調佇列)

362. 滑動視窗的最大值(單調佇列)

362.滑動視窗的最大值

中文English

給出一個可能包含重複的整數陣列,和一個大小為k的滑動視窗, 從左到右在陣列中滑動這個視窗,找到陣列中每個視窗內的最大值。

樣例

樣例 1:

輸入:
[1,2,7,7,8]
3
輸出:
[7,7,8]

解釋:
最開始,視窗的狀態如下:`[|1, 2 ,7| ,7 , 8]`, 最大值為 `7`;
然後視窗向右移動一位:`[1, |2, 7, 7|, 8]`, 最大值為 `7`;
最後視窗再向右移動一位:`[1, 2, |7, 7, 8|]`, 最大值為 `8`.

樣例 2:

輸入:
[1,2,3,1,2,3]
5
輸出:
[3,3]

解釋:
最開始,視窗的狀態如下: `[|1,2,3,1,2 | ,3]` , 最大值為`3`;
然後視窗向右移動一位.`[1, |2,3,1,2,3]`, 最大值為 `3`;

挑戰

O(n)時間,O(k)的額外空間

堆實現(heapq)

import heapq
class Solution:
    """
    @param nums: A list of integers.
    @param k: An integer
    @return: The maximum number inside the window at each moving.
    """
    def maxSlidingWindow(self, nums, k):
        # write your code here
        #堆實現
        
if len(nums) < k or not nums: return nums #初始化 length = len(nums) result = [] for i in range(length - k + 1): temp_array = nums[i: i + k] pop_num = temp_array[0] heapq._heapify_max(temp_array) result.append(temp_array[
0]) temp_array.remove(pop_num) return result

注:堆方法時間複雜度問題,未通過

雙端佇列(單調佇列)

from collections import deque
class Solution:
    """
    @param nums: A list of integers.
    @param k: An integer
    @return: The maximum number inside the window at each moving.
    """
    def maxSlidingWindow(self, nums, k):
        # write your code here
        if not nums: return []
        
        #雙端佇列(保持單調遞減)
        queue = deque([])
        length = len(nums)
        result = []
        count = 0 
        for i in range(length):
            #如果是當前元素 > 隊尾的話,需要pop掉隊尾元素,一直到滿足當前queue[-1] >= 當前元素 
            while count != 0  and queue[-1][0] < nums[i]:
                queue.pop()
                count -= 1 
            
            #如果是長度大於等於k的話,需要移除前面的元素,後面保持k個數量即可
            #注意,所謂的視窗移動,指的時nums的視窗移動,不是指的是queue保持在k長度,指的是nums的保持k長度
            if count != 0 and i - queue[0][1] >= k:
                queue.popleft()
                count -= 1 
            
            queue.append([nums[i], i])
            count += 1 
            
            #開始往result裡面加的話,此時則說明i是大於等於k - 1 ,隊首即為最大的元素
            if (i >= k - 1):
                result.append(queue[0][0])
        
        return result
            
        

下面版本也可以

class Solution:
    """
    @param nums: A list of integers.
    @param k: An integer
    @return: The maximum number inside the window at each moving.
    """
    def maxSlidingWindow(self, nums, k):
        # write your code here
        if not nums: return []
        
        #雙端佇列
        queue = []
        length = len(nums)
        result = []
        count = 0 
        for i in range(length):
            #如果是當前元素 > 隊尾的話,需要pop掉隊尾元素,一直到滿足當前queue[-1] >= 當前元素 
            while count != 0  and queue[-1][0] < nums[i]:
                queue.pop()
                count -= 1 
            
            #如果是長度大於等於k的話,需要移除前面的元素,後面保持k個數量即可
            #注意,所謂的視窗移動,指的時nums的視窗移動,不是指的是queue保持在k長度,指的是nums的保持k長度
            if count != 0 and i - queue[0][1] >= k:
                queue.pop(0)
                count -= 1 
            
            queue.append([nums[i], i])
            count += 1 
            
            #開始往result裡面加的話,此時則說明i是大於等於k - 1 ,隊首即為最大的元素
            if (i >= k - 1):
                result.append(queue[0][0])
        
        return result