8.25数组滑动窗口最值 - WisperDin/blog GitHub Wiki
描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值
例如,如果输入数组{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},最大值4 {2,[3,4,2],6,2,5,1},最大值4 {2,3,[4,2,6],2,5,1},最大值6 {2,3,4,[2,6,2],5,1},最大值6 {2,3,4,2,[6,2,5],1},最大值6 {2,3,4,2,6,[2,5,1]},最大值5
思路
可以使用队列,描述滑动窗口这个先进先出的模型,问题转化成,求队列中的最大值
假设从第一个窗口开始,一直往后滑动,往队列加入新元素时:
- 将当前队列中比新元素小的元素pop
- 将不属于当前窗口的元素pop出
通过这种方式,使得队列的队首始终是当前窗口的最大值
实现
package ShiftWindows
import (
"container/list"
)
func ShiftWindows(arr []int, size int) []int {
if size<=0 {
return nil
}
if len(arr)<size {
return nil
}
q:=list.New()
//first windows
for i:=0;i<size;i++{
if q.Len()!=0 && arr[i]>= arr[q.Back().Value.(int)] {
q.Remove(q.Back())
}
q.PushBack(i)
}
ans := []int{}
//next windows
for i:=size ; i< len(arr) ; i++ {
//每次循环都是在考察一个窗口的最值, i 为该窗口的最后一个元素位置
//1. pop-tail 队列中比当前值要小的元素 for
//2. pop-front 队列中不属于当前窗口的元素 if
//3. push当前元素
//根据1,2 每次执行后的队首都是当前窗口的最大元素
//当前队首为上一个窗口的最值
ans = append(ans, arr[q.Front().Value.(int)])
//从队尾开始考察是否有比当前值要小的元素,有则pop
for q.Len()!=0 && arr[i]>= arr[q.Back().Value.(int)] {
q.Remove(q.Back())
}
//删除队列中比当前考察值要大且在窗口外的元素
//上一个窗口最值位置 不在本次搜索最值的窗口内
if q.Len()!=0 && q.Front().Value.(int) < i-size+1{
q.Remove(q.Front())
}
q.PushBack(i)
}
//最后一个结果
ans = append(ans, arr[q.Front().Value.(int)])
return ans
}