• 打败算法 —— 滑动窗口最大值


    本文参考

    出自LeetCode上的题库 —— 滑动窗口最大值,一般的双指针解法会导致时间超时,需要借助大根堆(大顶堆)实现

    https://leetcode-cn.com/problems/sliding-window-maximum/

    滑动窗口最大值问题

    给定一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧,每次只向右移动一位

    返回滑动窗口每次移动后,窗口中的最大值

    示例1:
    输入:nums = [1, 3, -1, -3, 5, 3, 6, 7], k = 3
    输出:[3, 3, 5, 5, 6, 7]
    解释:
    滑动窗口的位置 最大值
    --------------- -----
    [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

    解题思路

    第一种解法是直接利用双指针,让$left$和$right$指针每次向右移动一个位置,每次移动后求取窗口内子串的最大值。但这种直观的思路会导致时间超时,若数组的长度为$n$,窗口长度为$k$,时间复杂度为$O(nk)$

    第二种解法是借助python的heapq小根堆函数库,如果需要大根堆的效果,只需对数组的每个值取负值。创建堆的时间复杂度为$O(n)$,修改堆的时间复杂度为$O(logn)$,这时可能会问,我每次从堆里删除不在窗口中的元素,再向堆里插入窗口中新增的元素,还是很耗时啊?实际上,我们不需要在窗口移动时,每次都删除堆中不需要的元素,只要保证堆顶的元素在窗口中就行,从而减少堆的pop操作

    双指针解法(超时)

    class Solution:
      def
    max_sliding_window(self, nums: List[int], k: int) -> List[int]:
        left = 0
        right = k
        ans = list()
        while right <= len(nums):
          curr = max(nums[left:right])
          ans.append(curr)
          left += 1
          right += 1
        return ans

    大根堆解法(nlogn)

    def max_sliding_window(self, nums: List[int], k: int) -> List[int]:
      n = len(nums)
      # 默认是小根堆,添加负号变成大根堆 

      q = [(-nums[i], i) for i in range(k)]
      heapq.heapify(q)

      ans = [-q[0][0]]
      for i in range(k, n):
        heapq.heappush(q, (-nums[i], i))
        # 不断地移除堆顶的元素,直到其确实出现在滑动窗口中 

        while q[0][1] <= i - k:
          heapq.heappop(q)
          ans.append(-q[0][0])
      return ans

  • 相关阅读:
    find
    Spring 中——————ClassPathResource初学
    Cookie 、Session、Token的学习
    JAVA注解之实现原理
    JAVA注解---2
    JAVA注解————1
    函数式遍程----Function
    java 反射的学习实践2
    Spring AOP 之动态代理源码分析
    正则表达式之Pattern.MULTILINE Pattern.DOTALL
  • 原文地址:https://www.cnblogs.com/kuluo/p/15991014.html
Copyright © 2020-2023  润新知