leetcode 239 滑动窗口最大值

题目

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 。

示例

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置     最大值


[1 3 -1] -3 5 3 6 7     3
1 [3 -1 -3] 5 3 6 7     3
1 3 [-1 -3 5] 3 6 7     5
1 3 -1 [-3 5 3] 6 7     5
1 3 -1 -3 [5 3 6] 7     6
1 3 -1 -3 5 [3 6 7]     7

解析

这道题是使用单调队列(注意既不是优先级队列top K,也不是普通的先入先出队列,而是单调队列),队列中的队首是最大值;
在压入队列时,判断队列末尾的元素值如果小于要加入的值,则循环删除,保证队首最大;

func maxSlidingWindow(nums []int, k int) []int {
   var ans []int
   var queue []int
   for i, num := range nums {
   	// 1.入队列(元素入队尾,同时要满足队列的单调性)
   	for len(queue) > 0 && nums[queue[len(queue)-1]] <= num {
   		queue = queue[:len(queue)-1]
   	}
   	queue = append(queue, i) // 入的是下标
   	// 2.出队列(元素离开队首),出队列的条件是此时的下标比减去窗口起始位置的下标,大于K
   	if i-queue[0] >= k {
   		queue = queue[1:]
   	}
   	// 3.记录答案
   	if i >= k-1 { // 这一步主要是用于拦截最开始长度不够K的时候,比如K=3,i是下标要大于等于2的时候,才够第一个窗口
   		// 由于队首到队尾是单调递减,所以窗口最大值就是队首
   		ans = append(ans, nums[queue[0]])
   	}
   }
   return ans
}

也可以用下面的代码,都差不多,上面在数组中存的是下标,下面存的是具体的值

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)
}
//上面这三个相当于C++中可以直接使用的dqueue

func (m *MyQueue) Pop(val int) {
   if !m.Empty() && val == m.Front() { //只有队列的队首元素等于需要弹的元素时才弹出
       m.queue = m.queue[1:]
   }
}

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 maxSlidingWindow(nums []int, k int) []int {
   queue := NewMyQueue()
   res := []int{}
   //先将前K个元素加入队列
   for i:=0; i < k; i++ {
       queue.Push(nums[i]) //比如是1 3 -1,则此时队列中是3 -1
   }

   //记录前K个元素的最大值
   res = append(res, queue.Front())

   for i:=k; i < len(nums); i++ {
       queue.Pop(nums[i-k]) //先弹出最开头的元素、
       queue.Push(nums[i]) //压入新的元素
       res = append(res, queue.Front()) //将单调栈中的第一个元素(最大的)放进结果集中
   }
   return res
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值