刷刷刷 Day 13 | 239. 滑动窗口最大值

239. 滑动窗口最大值
LeetCode题目要求

给你一个整数数组 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
解题思路

本题有些难度,如果不考虑时间复杂度,可以通过队列方式。大致思路是,队列中始终保持 3 个元素,满 3 个后找到最大值放入结果集,由于是队列,最大值不一定在最前方,那么需要遍历找到对应的值 poll 出来,而过程中其他的元素便于二次使用需要再次入队;然后再把对头元素 pool 出来。重复过程知道所有元素都遍历完成。
参考 carl 的自定义单调队列,可以简化滑动窗口的操作过程。具体直接看代码中的注释说明吧。

上代码

class MyQueue {
    // 自定义的队列实现,通过双端队列实现
    // 包含了 poll 头元素方法;offer 放入元素方法;getMax 方法即取队列头元素

    Deque<Integer> deque = new LinkedList<>();

    /**
     * poll(int val) 方法根据给定的元素,如果与队列头元素相等,那么出队
     */
    public void poll(int val) {
        if (!deque.isEmpty() && val == deque.peek()) {
            deque.poll();
        }
    }

    /**
     * offer(int val) 入队给定的元素,当给定值大于队尾元素,那么将队尾所有小于给定值的元素全部移除队列,即队内保证单调递减元素存在; 亦可理解为,如果队列中已存在的元素值没有新元素值大,那么就把他们抛弃,如果新元素值小于队列内元素值时才放入。保证队列单调递减
     */
    public void offer(int val) {
        while (!deque.isEmpty() && val > deque.peekLast()) {
            deque.removeLast();
        }
        deque.offer(val);
    }

    /**
     * 获取队列最大值,由于队列保持的单调递减存储,那么获取最大值,即取对头元素
     */
    public int getMax() {
        return deque.peek();
    }

}
class Solution {

    public int[] maxSlidingWindow(int[] nums, int k) {

        MyQueue q = new MyQueue();
        // 先将给定 k 个元素放入自定义队列中
        for (int i = 0; i < k; i++) {
            q.offer(nums[i]);
        }

        // 计算返回结果的数组长度,用数组长度 - 滑动窗口长度 + 1
        int len = nums.length - k + 1;
        // rr 数组用于存储结果
        int[] rr = new int[len];
        // rr 数组下标索引
        int rrIndex = 0;
        // 由于 q 内进行了一个窗口的操作,这里第一次先取出第一个最大值放入结果数组 rr
        rr[rrIndex++] = q.getMax();

        // 从 k 位置开始,遍历 nums 数组,逐个放入 q
        for (int i = k; i < nums.length; i++) {
            // 移除窗口内的最前面的元素,移除一个
            q.poll(nums[i - k]);
            // 将当前元素放入窗口,并做 deque 的 offer 操作
            q.offer(nums[i]);
            // 以上操作后,又保证了当前窗口内的最大值已经在 单调队列的 第一个了。将最大值放入结果 rr
            rr[rrIndex++] = q.getMax();
        }

        return rr;
    }
}
重难点

掌握队列的操作,尤其是双端队列对于元素的操作。同时自定义的队列是一个单调递减的队列,通过三个方法完成了每次可以取到窗口中最大值的过程。
附:学习资料链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值