LeetCode 239. 滑动窗口最大值

题目链接:LeetCode 239. 滑动窗口最大值

题意:

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

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

解题思路:

(单调队列) O(n)

使用单调队列求解滑动窗口中的最大值。其中,单调队列是一个普通的双端队列,即队头和队尾都可以添加和弹出元素。我们假设该双端队列的 队头 是整个队列的最大元素所在下标,至 队尾 下标代表的元素值依次降低。
初始时单调队列为空。随着对数组的遍历过程中,每次插入元素前,需要考察两个事情:
(1). 合法性检查:队头下标如果距离 i 超过了 k ,则应该出队。
(2). 单调性维护:如果 nums[i] 大于或等于队尾元素下标所对应的值,则当前队尾再也不可能充当某个滑动窗口的最大值了,故需要队尾出队。始终保持队中元素从队头到队尾单调递减。
如次遍历一遍数组,队头就是每个滑动窗口的最大值所在下标。
时间复杂度
遍历中,每个元素最多进队一次,出队一次,故时间复杂度为 O(n)。
空间复杂度
需要额外 O(n) 的空间存储单调队列。

完整代码如下:

func maxSlidingWindow(nums []int, k int) []int {
    // 单调队列的思想  只要右边的数比左边的大,那么左边的就没有意义,可以直接去掉

    var q []int   //存放滑动窗口中的数的下标
    var res []int   //存放结果
    for i:=0;i<len(nums);i++{

        if len(q)>0 && i-k+1 > q[0]{   //i-k+1表示滑动窗口的左边界,左边界的下标大于q[0],说明q[0]应该退出滑动窗口
            q = q[1:]
        }

        for len(q)>0 && nums[i] >= nums[q[len(q)-1]] {  
            //如果当前nums[i]的值大于队尾 nums[q[len(q)-1]]的值,则删除队尾元素,当前值入队列。
            //因为是求滑动窗口最大值,因此如果当前的值比已经在队列中的值小,则永远不可能成为最大值,直接过滤掉即可
            q = q[:len(q)-1]
        }

        q = append(q,i)  //将当前元素的下标加入

        if i >=k-1{ //当前窗口里已经有k个元素,则将当前的队头(窗口最大值)加入到答案中
            res = append(res,nums[q[0]])
        }
    }

    return res

}
posted @ 2023-05-14 18:56  小星code  阅读(34)  评论(0)    收藏  举报