双端队列
滑动窗口内最大数
题目来源
LeetCode 239. Sliding Window Maximum
精简解题
方法一
- 构建大顶堆,大小为窗口大小k
- 窗口内数据入堆,返回最大值
- 窗口移动,提测内部移除数据,加入新入窗口数据,返回堆顶最大值
- 循环以上步骤,直到结束
// idx -> 2*idx+1, 2*idx+2
// (idx-1)/2 -> idx
func heappush(w []int, val int) []int {
var idx, idxN int = len(w), 0
w = append(w, val)
for idx > 0 {
idxN = (idx-1)/2
if w[idxN] < w[idx] {
w[idx], w[idxN] = w[idxN], w[idx]
} else {
break
}
idx = idxN
}
return w
}
func heappop(w []int) ([]int, int) {
var idx, idxN int = 0, 0
val := w[0]
w[0] = w[len(w)-1]
w = w[:len(w)-1]
for idx < len(w) {
idxN1, idxN2 := 2*idx+1, 2*idx+2
if idxN1>=len(w) || w[idxN1]<w[idx] {
idxN1 = 0
}
if idxN2>=len(w) || w[idxN2]<w[idx] {
idxN2 = 0
}
if idxN1>0 && idxN2>0 {
if w[idxN1]>w[idxN2] {
idxN = idxN1
} else {
idxN = idxN2
}
} else if idxN1>0 {
idxN = idxN1
} else if idxN2>0 {
idxN = idxN2
} else {
break
}
w[idx], w[idxN] = w[idxN], w[idx]
idx = idxN
}
return w, val
}
func maxSlidingWindow(nums []int, k int) []int {
if k==0 {
return []int{}
}
var window []int = make([]int, 0, k)
var dels []int = make([]int, 0)
var ans []int = make([]int, 0, len(nums)-k+1)
for i:=0; i<k; i++ {
window = heappush(window, nums[i])
}
ans = append(ans, window[0])
for i:=k; i<len(nums); i++ {
window = heappush(window, nums[i])
dels = heappush(dels, nums[i-k])
for len(dels)>0 && dels[0]==window[0] {
window,_ = heappop(window)
dels,_ = heappop(dels)
}
ans = append(ans, window[0])
}
return ans
}
方法二
- 构建双端队列
- 保持队列大小不超过窗口,以及最大值在出端
- 读取新数据,入端操作,和之前的进入的数据比较,之前的数据小则剔除,直到比它大则停止,最大值还在出端
- 循环上面步骤,直到结束
func maxSlidingWindow(nums []int, k int) []int {
//返回值
result := make([]int, 0, len(nums)-k)
//滑动窗口
window := make([]int, 0)
for i := 0; i < len(nums); i++ {
//双端队列的大小超过窗口大小k,则丢弃最早的值
if len(window) > 0 && window[0] <= i-k {
window = window[1:]
}
//新加入的值和之前加入的值比较,没有新值大的则出去
for len(window) > 0 && nums[window[len(window)-1]] < nums[i] {
window = window[:len(window)-1]
}
//双端队列,入口增加数据
window = append(window, i)
//开始存入最大值
if i >= k-1 {
result = append(result, nums[window[0]])
}
}
return result
}