sliding window问题

sliding window问题是一个经典问题。

给出一个长为n的数组,求每个长度为k的子区间的最小值。

比如:

n=5

序列为: 5,2,8,6,4,7

k=3

那么按照从左到右的顺序,所有长度为3的子区间的最小值分别是:

2,4,7

最简单的解法需要O(n*k)的复杂度。

通过维护window的“上升最小序列”可以在O(n)的时间内对于某一个k求出所有答案

 

一个序列W的“上升最小序列”A定义为:

A[0]=W中最小的元素

A[i]=W中在A[i-1]以后的最小的元素(i>=1)

 

这个序列显然是升序的,而且A[0]是W的最小元素。进一步观察不难发现,序列的最后一个元素一定是“上升最小序列”的最后一个元素。

 

如果能在子区间从左向右“滑动”的过程中,维护窗口的“上升最小序列”,那么窗口每向右滑动一格,就输出对应的“上升最小序列”的第一个元素

这样输出地就是要求的答案。

 

窗口的移动对子区间有两个影响:删除第一个元素,然后在最后插入一个元素。

维护窗口的“上升最小序列”很简单:

窗口向右移动一格之后,判断“上升最小序列”是否已经移出窗口。如果是,则删除“上升最小序列”第一个元素

对于新加入的元素,如果它不大于目前“上升最小序列”的第一个元素,那么显然新的“上升最小序列”只包含这个

新元素。如果它比第一个元素大,由于这个新元素注定要成为“上升最小序列”的最后一个元素,所以删除目前“上升最小序列”

尾部的大于等于新元素的所有元素,然后把新元素加到最后。

这样,就能保证窗口每滑动一次,得到的序列都是窗口的“上升最小序列”了。

 

注意到维护“上升最小序列”过程中只对头尾进行操作,于是可以用双端队列来存储。

要查询某个元素是否被移出窗口,可以对每个元素记录自己在窗口到达什么位置的时候会被移除。

 

代码参见:

http://home.tiac.net/~cri/2001/slidingmin.html

 

如果询问的k会变怎么办?

这样也可以用RMQ的方法来做。sliding window是RMQ的特例。

NlogN的DP+O(1)的时间可以找到任意区间的最小(大)值。

你可能感兴趣的:(sliding window问题)