力扣239.滑动窗口最大值

一、前言

力扣239.滑动窗口最大值

滑动窗口最大值,这道题给定一个数组,以及一个窗口的长度,这个窗口会往后滑动,直到数组最后一个元素。

要求每个滑动窗口的中的最大值。对于这道题,我刚看到的时候没有比较好的思路,心里想没思路?直接一个无脑暴力!

暴力的思路就是遍历数组的时候,每次遍历滑动窗口找出最大值!

果然,超时了。。。。。。

image-20241214155929713

遍历数组的时间复杂度是O(n),如果当滑动窗口的长度为n/2的时候,遍历滑动窗口找出最大值的时间复杂度是O(n),那么整体的暴力算法的时间复杂度是O(n²)。


二、单调队列

正所谓“空间换时间”,所以在这题中,想要降低时间复杂度,那就要牺牲一点空间,用空间来换时间。

这道题单看数组可能不是很直观,如果将数组转化为折线图,那么就能看出规则了!

假设现在有一个这样的数组,nums = [2,1,4,2,3,2], k = 3,该数组的折线图如下所示。

image-20241214161043730

[2,1,4]这个滑动窗口里面,最大值的4,但是2和1有没有可能作为滑动窗口的最大值呢?

这个是不可能的,因为4在2和1的右边,包含了1或2的滑动窗口必然包含了4,因此4会是最大值,而2和1没有机会成为最大值,于是就需要记录4。

随着滑动窗口往下往下滑动,那么滑动窗口为[1,4,2],最大值仍然为4,前面说了1是不可能有成为最大值的记录,那么这里的2有成为最大值的机会么?

很显然,是有可能的,因为2在4的右边,而且2后面的数字还不知道,有可能是比2小,并且在后面包含了2的滑动窗口中,可能不会包含4,因此2有可能成为最大值,于是需要将2记录下来。

窗口继续往下滑动,滑动窗口为[4,2,3],最大值为4,由于这次有3,3比2大,和前面一样,有3在,2不可能成为最大值,于是移除前面记录的2,而是将3进行记录。

窗口继续滑动,滑动窗口为[2,3,2],这时候4已经超出滑动窗口范围,需要在前面记录的数据中移除,于是这次滑动窗口的最大值就是3了

整体思路如上所示,这里需要用到一个数据结构——单调队列,思路如下:

  1. 入队列,将元素添加到队尾,并且需要维持队列的单调性(队列从大到小排序)
  2. 出队列,当元素超出滑动窗口的范围的时候,需要出队列
  3. 记录答案,每次滑动窗口的最大值就是队列的首部!
public int[] maxSlidingWindow(int[] nums, int k) {
    int[] res = new int[nums.length - k + 1];
    Deque<Integer> queue = new LinkedList<>();
    for (int i = 0; i < nums.length; i++) {
        while (!queue.isEmpty() && nums[i] > nums[queue.getLast()]){
            // 维持单调性
            queue.removeLast();
        }
        if (!queue.isEmpty() && i - queue.getFirst() >= k){
            queue.removeFirst();
        }
        queue.addLast(i);
        if (i >= k - 1){
            // 收集结果
            res[i - k + 1] = nums[queue.getFirst()];
        }
    }
    return res;
}

image-20241214162540951
解决!下班!!!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

起名方面没有灵感

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值