# 第24节 窗口内最大值或最小值的更新结构

# 滑动窗口是什么

滑动窗口是一种想象出来的数据结构:

滑动窗口有左边界L和有边界R

在数组或者字符串或者一个序列上,记为S,窗口就是S[L..R]这一部分

L往右滑意味着一个样本出了窗口,R往右滑意味着一个样本进了窗口

L和R都只能往右滑

  • R++,R向右动,数会从右侧进入窗口
  • L++,L向右动,数会从左侧滑出窗口
  • 遵循原则,左边界不能跑到右边界的右边去 L <= R

# 滑动内最大值和最小值的更新结构

窗口不管L还是R滑动之后,都会让窗口呈现新状况,

如何能够更快的得到窗口当前状况下的最大值和最小值?

最好平均下来复杂度能做到O(1)

利用单调双端队列(可从头部进,可从头部出,可从尾部进,可从尾部出,而且是O(1)的)

思路:

  • 准备数组[6,4,3,4,5,7,0,5],准备好双端队列(代表元素从头到尾是由大到小排列)
  • 窗口新增数时,当有数x滑进窗口时,如R++时,数x由尾部进入队列,双端队列头部代表的值就是窗口内最大值的位置
  • 再R++,判断数x是否能落在队列中已有数y的后面(y>x),若能则从尾部入,不能则从尾部弹出
  • 以上是R往右移动时的更新结构
  • 窗口减少数时,当有数X滑出窗口时,如L++时,从头部开始看下标有没有过期,若过期则弹出,反之不弹出,双端队列头部代表的值就是窗口内最大值的位置
  • 双端队列含义是:如果此时开始窗口缩小的话,哪些位置的数会依次成为窗口内的最大值

双端队列实现更新结构的好处与为什么快?

  • 数组中每个位置的数x,最多进入队列一次,出去队列一次,说明当窗口滑动时,队列内部更新的总代价是O(N),均摊下来的复杂度为O(1),窗口最大值的位置就是队列的头部元素,查询复杂度为O(1)

# 题目一

假设一个固定大小为W的窗口,依次划过arr, 返回每一次滑出状况的最大值 例如,arr = [4,3,5,4,3,3,6,7], W = 3 返回:[5,5,5,4,6,7]

代码:


1

# 题目二

给定一个整型数组arr,和一个整数num 某个arr中的子数组sub,如果想达标,必须满足: sub中最大值 – sub中最小值 <= num, 返回arr中达标子数组的数量

代码:


1

# 题目三

加油站的良好出发点问题

代码:


1

# 题目四

arr是货币数组,其中的值都是正数。再给定一个正数aim。 每个值都认为是一张货币, 返回组成aim的最少货币数 注意: 因为是求最少货币数,所以每一张货币认为是相同或者不同就不重要了

动态规划优化使用了窗口内最大值或最小值的更新结构

代码:


1