【leetcode239】【滑动窗口最大值】

leetcode 239 滑动窗口最大值

给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

示例:

输入: 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

解题思路:

  • 解法一【O(N·logK)】
    通常做最大值和最小值这种题目,我觉得使用优先队列(堆)是比较方便的,这里我们要求最大值,那么就维护一个size为K的堆,然后每次往后滑动,就扔掉第一个数,放入新元素,再次调整堆,调整堆的复杂度为O(logK),总共的时间复杂度为O(N·logK)

  • 解法二【O(N)】
    使用双端队列deque,双端队列的特点是可以从两端都入队和出队. 核 心 思 想 是 最 大 值 永 远 是 队 列 中 最 左 边 的 值 \color{red}{核心思想是最大值永远是队列中最左边的值} , 依次放入数据,这里我把先进来的值叫做A,后进来的值叫做B,如果B小于A,那么就放在A后面,如果B大于A,那么就把A出队,B就是队列的最左边的值,以此类推,每次返回最大值。这里做的优化是不需要去维护堆里的k个元素的大小顺序,只需要记录最大值即可,所以用heap就有点杀鸡用牛刀了。

代码思路:

  1. 表示代码严谨性,判断输入是否为空
  2. 两个数组,window存放下标,res存放结果
  3. window[0] <= i-k 是为了判断是否超过左边界,如果超出,就pop出来
  4. 逻辑重点,nums[window[-1]] <= x,意思是若输入的数比window里的元素大,就把window里的这些比它小的元素出队. 这里就像[3,1,2],2比1大,所以会把1从右边踢出去,放入2,最大值仍然为3,往后走一步,3会被踢出去,此时2就成最左边的值了,这里突出的思路每个元素只需要进入window一次,1进去一次就被踢出来了,不需要再重复判断,所以复杂度为O(1)

代码:

解法二:

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        if not nums or not k : return []
        window,res = [],[]
        for i,x in enumerate(nums):
            if i>=k and window[0]<=i-k: 	#如果window已经走过k个数字,并且超出了左边界
                window.pop(0) 				#踢出去最左边的元素
            while window and nums[window[-1]] <= x: 
            	window.pop()
           								 #如果window不为空,且新进来的元素,比你前面的元素大,
            							#那么把前面元素给踢掉,放入新元素
                
            window.append(i) #无论怎样都是要先进window一次的
            if i>=k-1:  #window走过了k个数字再开始记录res
                res.append(nums[window[0]])
        return res


复 杂 度 分 析 : \color{red}{复杂度分析:}

空间复杂度O(N),输出数组使用了 O ( N − k + 1 ) {O}(N - k + 1) O(Nk+1)空间,双向队列使用了 O ( k ) {O}(k) O(k)
时间复杂度O(N)每个元素被处理两次:其索引被添加到双向队列中和被双向队列删除。

进阶分析:

打算实现一下解题思路:
第一个想到的是暴力法,遍历每个滑动窗口,找到每个窗口最大的值,一共N-k+1个滑动窗口,每个有K个元素,时间复杂度为 O ( N ⋅ K ) O(N·K) O(NK)

class Solution:
    def maxSlidingWindow(self, nums: 'List[int]', k: 'int') -> 'List[int]':
		n = len(nums)
		if n*k == 0:  #判断nums和k是否为空
			return []
		res = []
		for i in range(n-k+1):
			res.append(max(nums[i:i+k]))
		return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值