原始问题分析
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。
常规解法:时间复杂度为$O(N * w)$,也就是每次对一个窗口都需要遍历其中的 w 个数,选出最大值。
$O(N)$解法:准备一个双端队列,双端队列存放着数组中的下标值。假设当前为 arr[i],则放入规则如下:
left 和 right 指针都只会向右移动,不会回退。
- right 右滑,窗口加数:
1)如果 queue 为空,直接把下标 i 放入 queue 中;
2)如果 queue 不为空,取出当前 queue 队尾存放的下标 j。如果 arr[j] > arr[i],则直接把 i 放入队尾;
3)如果 arr[j] <= arr[i],则一直从 queue 的队尾弹出下标,直到某个下标在 queue 中的对应值大于 arr[i],然后把 i 放入队尾 【为什么可以弹出,因为我永远比你晚过期,我又比你大或者和你一样大,有我在,你永远不可能最大,所以你可以弹出了】 - left 右滑,窗口减数:
1)看弹出的 left 是否与队列头相等,如果相等,说明这个队列头已经不在窗口内了,所以弹出 queue 当前的队首元素 。
双端队列的队头就是当前窗口最大值的下标。
应用
上面的滑动窗口的实现是通用结构,即 left 和 right 指针随便往右移,而在实际解题过程在,都是会限制窗口的大小。
1. 剑指offer:滑动窗口的最大值
题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
常规解法:
时间复杂度为O(N * w),也就是每次对一个窗口都需要遍历其中的 w 个数,选出最大值。
1 | # -*- coding:utf-8 -*- |
$O(N)$解法:
和通用结构相比。只在弹出时稍微改变:
如果queue对应的下标等于i-size, 说明当前队首下标已经过期,则弹出queue当前队首下标。
1 | from collections import deque |
2. 最大值减去最小值小于或等于num的子数组数量
给定数组arr和整数num,返回有多少个子数组满足如下情况:
$max(arr[i:j]) - min(arr[i:j]) <= num$
$max(arr[i:j])$表示子数组$arr[i:j]$中的最大值,$min(arr[i:j])$表示子数组$arr[i:j]$中的最小值。
要求:如果数组长度为 N,请实现时间复杂度为 O(N)的解法。
解题思路
子数组的数量:
以0开始:0~0,0~1,...,0~N-1
,共N种情况;
以1开始:1~1,1~2,...,1~N-1
,共N-1种情况;
……
以N-1开始:N-1~N-1
,共1种情况。
所以总共有 $N+N-1+N-2+…+2+1=\frac{N(N-1)}{2}$种情况。
暴力解法:
两层遍历所有情况,一层遍历求最大最小值,共三层遍历,时间复杂度$O(N^3)$。
1 | # -*- coding:utf-8 -*- |
$O(N)$解法:
两个结论:
- 如果子数组arr[i:j]满足条件,那么arr[k:l](i<=k<=l<=j)一定满足条件,即若一个数组满足条件,它的所有子数组肯定满足条件,因为[max 变小 - min 变大 <= num 肯定成立]。
- 如果子数组 arr[i:j] 不满足条件,那么 arr[k:l] (k <= i,I >= j) 都不满足条件,即若一个数组不满足条件,所有包含它的数组肯定都不满足条件。因为[max变大 - min变小 >= num肯定成立]。
步骤:
准备两个双端队列,一个 maxQueue 是窗口内最大值更新结构,一个 minQueue 是窗口内最小值更新结构,left、right 表示窗口的左右边,窗口范围为 [left , right - 1];算以 left 开头达标的子数组个数,每个 left 就可以算出一批答案,相加即可。
- 1)以 left 开头的情况下,right 往外扩,扩到不达标就停【因为再往外肯定也不达标】,算以 left 开头的子数组有多少个【这些子数组都达标的】;
- 2)left 右移一位,然后重复 1)。
因为 left,right 都不后退,且每个数都只进出一次,所以时间复杂度是 $O(N)$。
1 | from collections import deque |
参考文献:
https://blog.csdn.net/pcwl1206/article/details/96431668
https://www.cnblogs.com/xieyupeng/p/10373585.html