滑动窗口算法_算法刷题(2):返回滑动窗口最大值

题目:Sliding Window Maximum

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the knumbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.

例子:

Input: nums = [1,3,-1,-3,5,3,6,7], and k = 3Output: [3,3,5,5,6,7]

题目解释:

即给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。

例如,如果输入数组[1, 3, -1, -3, 5, 3, 6, 7]及滑动窗口的大小k=3,那么一共存在6个滑动窗口:

Window position Max

[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

解法1:

暴力求解法,扫描滑动窗口中的每一个数字,并找出其中的最大值。如果滑动窗口的大小为k,对于长度为n的数组,有n-k+1个窗口,所以总的遍历次数为k * (n-k+1),时间复杂度为O(k*n)。

输入数组[1, 3, -1, -3, 5, 3, 6, 7],滑动窗口的大小k=3

Window position Max

[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

解法2:

借助一个双端队列,即可以在队头插入或删除元素,也可以在队尾插入或删除元素,然后遍历数组,根据如下规则进行入队列或出队列操作:

1. 如果队列为空,则当前数字入队列

2. 如果当前数字大于队列尾,则删除队列尾,直到当前数字小于等于队列尾,或者队列空,然后当前数字入队列

3. 如果当前数字小于队列尾,则当前数字入队列

4. 如果队列头超出滑动窗口范围,则删除队列头

这样能始终保证队列头为当前的最大值,而且从队头到队尾为递减的序列!

现在进一步举例说明为什么要这么做,以及为什么这样做能找到每个滑动窗口中的最大值。

还是上述的例子:

输入数组[1, 3, -1, -3, 5, 3, 6, 7]

滑动窗口的大小k=3

首先,遍历数组中第一个元素,双端队列为空,元素1入队。

f4d4342c75fea8072185160e9e0f8412.png

遍历数组第二个元素为3,因为3比1大,1出队,3入队.

b451fc83565d98f01415c84d1c1377fb.png

遍历数组第三个元素为-1,-1比3小,-1直接从队尾入队。此时滑动窗口刚好经过三个元素,以-1为结尾元素的滑动窗口[1, 3, -1]内的最大值就是队列的头元素,也就是3;

8689ee7bf56159379d937a4ceae814a4.png

遍历数组第四个元素为-3,-3比-1小,而且队首元素3的和即将插入的元素-3之间的窗口没有大于窗口k的值(若大于窗口k的值,那么队首元素出队),然后-3直接从队尾入队。所以以-3为结尾的滑动窗口[3, -1, -3]内的最大值还是队列的头元素,也就是3;

c594f85673fa5500637831d9c253dd18.png

遍历数组的第五个元素为5,队首元素3的和即将插入的元素5之间的窗口大于窗口k的值,因此队首元素已经不在以5为结尾的滑动窗口内,所以我们把让队首元素3出队,然后5分别大于-3、-1,所以-3、-1出队,接着5从队尾进队,此时以5为结尾的滑动窗口[-1, -3. 5]内的最大值为5.

3f90a1a013e1f3024f79290e78ec76fb.png

遍历数组的第六个元素为3, 3小于5,3直接从队尾入队,此时以3为结尾的滑动窗口[-3, 5, 3]内的最大值为队首元素5.

afb2737abc06c13a2e02b0b1f91729fb.png

遍历数组的第七个元素为6,因为6分别大于3、5,因此3、5依次出队,然后6从队尾进队。此时以6为结尾的滑动窗口[5, 3, 6]内的最大值为6.

9b17f94d976fa297c6cdd3bc93029aa4.png

遍历数组数组的第八个元素为7,因为7大于6,因此6出队,然后7从队尾进队,此时以7为结尾的滑动窗口[3, 6, 7]内的最大值为7.

21100cfa748eb0513584a09160cf3fb7.png

java代码如下

import java.util.*;class Solution { public int[] maxSlidingWindow(int[] nums, int k) {if (nums == null || k <= 0) { return new int[0]; } ArrayDeque q = new ArrayDeque<>(); int[] res = new int[nums.length - k + 1]; for(int i=0; i nums[q.peekLast()]){ q.pollLast(); } else break; } q.addLast(i); //当遍历数组的个数开始满足窗口值时,开始记录窗口内最大值 if(i >= k-1) res[i+1-k] = nums[q.peekFirst()]; } return res; }}

好了,今天的算法刷题到此为止讲述完毕,如果您对题目有更好的解法或者更好的想法,或者您对题目有什么疑惑或者我讲错的地方,又或者您有其他的有趣的题目想让我们讲解的,欢迎评论区留言告诉我们,我们一定进行回复,让我们共同交流共同进步!

IT界的泥石流带你一同刷题!一同进步!一同成长!

欢迎关注我们的微信公众号:IT界的泥石流

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值