【leetcode】239. Sliding Window Maximum

在这里插入图片描述
求滑动窗口括起来的数组中的最大值。
最简单的方法就是暴力法,但时间复杂度为O(nk),这种hard题暴力法不用想都知道是不能过的。

思路1:

使用双端队列。用双端队列作为存储空间,存储方法如下

  • 从左往右依次遍历数组,如果队列为空,那么将当前元素的添加到队列的左边(index和元素是一一对应的,入栈index相当于入栈了元素)
  • 如果当前队列不为空,且当前元素小于等于队列最右端元素,那么将当前元素加入对垒最右边
  • 否则,对队列进行pop操作,直到队列最右元素大于等于当前元素或队列为空
  • 将当前元素处理过后,判断队列最左边的元素是否在滑动窗口的范围内,如果不在则删除(这就是为什么要存储下标而不存储值的原因)

AC代码

class Solution:
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        res = []
        if k==0:
            return res
        from collections import  deque
        queue = deque()
        for i in range(len(nums)):
            while(len(queue)!=0 and nums[queue[-1]]<nums[i]):
                queue.pop()
            while(len(queue)!=0 and queue[0]<=i-k):
                queue.popleft()
            queue.append(i)
            if i+1 >= k:
                 res.append(nums[queue[0]])
        return res

思路2:

一般这种子区域的最大值或最小值都会想到用堆来做,但是堆一般只能pop最大或最小值,滑动窗口每次都要删除最左边的一个元素,所以要对堆进行小小的改进,加一个remove元素的方法,这里就不自己写方法了,使用python标准库的heapq,他可以将数组变成堆数组,每次删除元素后重新建立堆即可,时间复杂度为O(nk)(查找要删除的元素得顺序遍历)

class Solution:
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        res = []
        import  heapq
        pq = []
        for i in range(len(nums)):
            if i>=k-1:
                index = -1
                for j in range(len(pq)):
                    if pq[j] == -nums[i-k]:
                        index = j
                        break
                # print(pq.queue,index)
                if index!=-1:
                    del pq[index]
                heapq.heappush(pq, -nums[i])
                heapq.heapify(pq)
                res.append(-pq[0])
            else:
                heapq.heappush(pq,-nums[i])
        return res

思路3

disscuss中某大神的思路
拿题目中nums = [1,3,-1,-3,5,3,6,7], and k = 3为例
先根据k将数组分成一个个k的子数组
1 3 -1 | -3 5 3 | 6 7]
假设在第i个元素的时候,用max_leftmax_right分别表示,i左边元素的最大值和i右边元素的最大值(包括自己),注意这里的最大值是到边界为止的最大值(上面的|为边界)
,这样我们就能得到两个数组maxleft和maxright,这样,当前窗口的最大值为max(maxright(array_start),maxleft(arrat_end))
1 3 (-1 | -3 5 ) 3 | 6 7]
非常巧妙

class Solution:
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        if k ==0:
            return []
        maxleft = nums[:]
        maxright = nums[:]
        flag_left = nums[0]
        flag_right = nums[-1]
        for i in range(len(nums)):
            left_index = i
            right_index = len(nums)-i-1

            if (left_index) % k==0:
                flag_left =nums[left_index]
            else:
                flag_left =max(nums[left_index],flag_left)
            maxleft[left_index] = flag_left

            if (right_index+1) % k ==0:
                flag_right = nums[right_index]
            else:
                flag_right = max(nums[right_index],flag_right)
            maxright[right_index] =flag_right
        res = []
        for i in range(k-1,len(nums)):
            res.append(max((maxleft[i]),maxright[i-k+1]))
        return res
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页