239. 滑动窗口最大值
解法1:暴力
两层for循环,不再演示
解法2:单调队列
// 封装单调队列的方式解题
type MyQueue struct {
queue []int
}
func NewMyQueue() *MyQueue {
return &MyQueue{
queue: make([]int, 0),
}
}
//返回队头元素
func (m *MyQueue) Front() int {
return m.queue[0]
}
//返回队尾元素
func (m *MyQueue) Back() int {
return m.queue[len(m.queue)-1]
}
//判断队列是否为空
func (m *MyQueue) Empty() bool {
return len(m.queue) == 0
}
//入队
func (m *MyQueue) Push(val int) {
for !m.Empty() && val > m.Back() {
m.queue = m.queue[:len(m.queue)-1]
}
m.queue = append(m.queue, val)
}
//出队
func (m *MyQueue) Pop(val int) {
if !m.Empty() && val == m.Front() {
m.queue = m.queue[1:]
}
}
func maxSlidingWindow(nums []int, k int) []int {
queue := NewMyQueue()
length := len(nums)
res := make([]int, 0)
// 先将前k个元素放入队列
for i := 0; i < k; i++ {
queue.Push(nums[i])
}
// 记录前k个元素的最大值
res = append(res, queue.Front())
for i := k; i < length; i++ {
// 滑动窗口移除最前面的元素
queue.Pop(nums[i-k])
// 滑动窗口添加最后面的元素
queue.Push(nums[i])
// 记录最大值
res = append(res, queue.Front())
}
return res
}
其核心思想参考代码随想录视频
最不好理解的就是
Push
和Pop
两个操作
找个例子多模拟两边就能理解,但要熟练掌握还是有点难度
每次入队操作,都要判断val是否大于队列中最后一个元素以保证队列中的单调性 (不是严格的单调)
每次出队操作,都要判断是否出队的是val是否是队头元素,若是的话则出队,若不是则不用理会
这样能保证队头元素是最大的,第二个元素就是次大的
此题单调队列,但不要抠字眼
1.不完全单调,因为要保证队头元素是最大的
2.也不完全是队列的属性,虽然出队入队符合规则,但再在入队操作时,有可能把队尾元素拿掉