【滑动窗口】力扣239.滑动窗口最大值

2024-03-10 15:28

本文主要是介绍【滑动窗口】力扣239.滑动窗口最大值,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前面的文章我们练习数十道 动态规划 的题目。相信小伙伴们对于动态规划的题目已经写的 得心应手 了。

还没看过的小伙伴赶快关注一下,学习如何 秒杀动态规划 吧!

接下来我们开启一个新的篇章 —— 「滑动窗口」

滑动窗口

滑动窗口 是一种基于 双指针 思想的算法。两个指针指向的元素之间会形成一个窗口,从前往后遍历元素进行一定的运算。

从名字中也不难看出:滑动 说明窗口的大小并不是固定不变的。通过左右指针按照 规则 向前滑动形成的不同大小的窗口解决具体的问题。

因此,分析问题的 关键 就在于 明确两个指针的移动规则

核心步骤

  1. 初始时,L = R = 0 ,并规定窗口的取值为 [L, R) 即:左闭右开 。因此,初始时[0, 0) 无意义,窗口内没有任何元素被包含。

  2. 循环遍历,在保证不会越界的情况下,不断 增大右指针R。当满足要求后,停止增大右指针R

  3. 左指针L开始 不断增大,直到不满足要求后停下。

  4. 重复执行 2、3 两步,直到右指针R走到尽头( 越界 )。

左右指针轮流向前移动,窗口大小不断变化。新旧元素加入和移出后,及时更新该窗口范围内的相关数据。当执行结束后,收集到了所有符合要求的数据,且时间复杂度降低到了 O ( N ) O(N) O(N)


下面我们通过一道 力扣 Hard 题 进行学习。

239. 滑动窗口最大值

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


在解决该题目之前,我们先来讨论一下这类题的套路。

思路与套路

对于 窗口内最大最小值 的题目,我们采用 双端队列 的结构进行思考。并对 出队入队 进行这样的规定(以窗口内的最大值举例):

队列含义:
  1. 如果此时开始缩窗口(即:L++),哪些值会依次成为此时窗口内的最大值。
  2. 要求,队列中的元素从大到小排列。
队列的出入:

队尾 的出队与入队:

  • 如果队空,直接入队;
  • 否则,如果队尾位置不大于当前来到位置的数,从队尾出队。直到队尾元素大于当前位置元素,从队尾入队。

队头 的出队:

  • 当窗口缩小时,若队头元素已经不在当前的窗口中时,从队头弹出即可。

是不是没搞懂在说什么,没关系。我们通过具体的例子感受该流程:

就拿例 1 的例子,nums=[1,3,-1,-3,5,3,6,7],构造双端队列的值依次为:

注意: 双端队列中 队头元素 保存的是 当前范围最大值

先看从队尾出入队的情况:



以上均是 L 不动,R 在右移的情况。

再看从队头出队的情况:

下面我们再来看 L 也向右移动的情况:

L 指向 1,R 指向 5 时为例:


跟着图细心体会该过程哦!相信小伙伴能够理解双端队列的出入规则了!


下面我们回归正题,解决上面力扣 滑动窗口最大值 的题目。

仔细思考后发现,其实就是将上面的过程 加以限制

限制了窗口的大小必须为 k 。

直接上代码。

代码

public static int[] getMaxWindow(int[] arr, int w) {if (arr == null || w < 1 || arr.length < w) {return null;}// 双端队列LinkedList<Integer> qmax = new LinkedList<Integer>();int N = arr.length;// 最终会产生 N - w + 1 个结果int[] res = new int[N - w + 1];// res 数组的下标int index = 0;// R 从左到右遍历数组,不回退for (int R = 0; R < N; R++) {// 双端队列中有值,并且 队尾的数 比当前的 小 就弹出while (!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[R]) {qmax.pollLast();}// 双端队列为空,或者弹出完比自己小的数了// 从末尾插入队列中qmax.addLast(R);// R-w 是过期的下标,即 L 的位置// 队头的下标 过期了就弹出if (qmax.peekFirst() == R - w) {qmax.pollFirst();}// 能够形成完整的窗口了,开始往 结果数组 里填最终答案if (R >= w - 1) {res[index++] = arr[qmax.peekFirst()];}}return res;
}

代码解释

其实注释已经写的非常清楚了。

  1. 在上面的图中,我么在双端队列中放入的是 元素值,但在实际的代码中,存入的是下标,这样的话既能够比较大小,又能方便的进行入队出队操作。
  2. 窗口大小固定,R 和 L 一起右移。因此若判断出队头元素已经离开了窗口,就要弹出。
  3. 刚开始,R 从 0 开始增大,窗口还未形成。只有当形成 k 大小的窗口后再开始更新答案。(那 思考一下 为什么不直接从下标 k 开始呢?这不直接就有窗口了么?欢迎留言评论 ~)

~ 点赞 ~ 关注 ~ 星标 ~ 不迷路 ~!!!

关注回复「ACM紫书」获取 ACM 算法书籍~

这篇关于【滑动窗口】力扣239.滑动窗口最大值的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/794676

相关文章

使用JS/Jquery获得父窗口的几个方法(笔记)

<pre name="code" class="javascript">取父窗口的元素方法:$(selector, window.parent.document);那么你取父窗口的父窗口的元素就可以用:$(selector, window.parent.parent.document);如题: $(selector, window.top.document);//获得顶级窗口里面的元素 $(

两数之和--力扣1

两数之和 题目思路C++代码 题目 思路 根据题目要求,元素不能重复且不需要排序,我们这里使用哈希表unordered_map。注意题目说了只对应一种答案。 所以我们在循环中,使用目标值减去当前循环的nums[i],得到差值,如果我们在map中能够找到这个差值,就说明存在两个整数的和为目标值。 如果没有找到,就将当前循环的nums[i]以及下标i放入map中,以便后续查

专题二_滑动窗口_算法专题详细总结

目录 滑动窗口,引入: 滑动窗口,本质:就是同向双指针; 1.⻓度最⼩的⼦数组(medium) 1.解析:给我们一个数组nums,要我们找出最小子数组的和==target,首先想到的就是暴力解法 1)暴力: 2)优化,滑动窗口: 1.进窗口 2.出窗口 3.更新值 2.⽆重复字符的最⻓⼦串(medium) 1)仍然是暴力解法: 2)优化: 进窗口:hash[s[rig

力扣第347题 前K个高频元素

前言 记录一下刷题历程 力扣第347题 前K个高频元素 前K个高频元素 原题目: 分析 我们首先使用哈希表来统计数字出现的频率,然后我们使用一个桶排序。我们首先定义一个长度为n+1的数组,对于下图这个示例就是长度为7的数组。为什么需要一个长度为n+1的数组呢?假如说总共有三个数字都为1,那么我们需要把这个1放在数组下标为3的位置,假如说数组长度为n,对于这个例子就是长度为3,那么它的

hot100刷题第1-9题,三个专题哈希,双指针,滑动窗口

求满足条件的子数组,一般是前缀和、滑动窗口,经常结合哈希表; 区间操作元素,一般是前缀和、差分数组 数组有序,更大概率会用到二分搜索 目前已经掌握一些基本套路,重零刷起leetcode hot 100, 套路题按套路来,非套路题适当参考gpt解法。 一、梦开始的地方, 两数之和 class Solution:#注意要返回的是数组下标def twoSum(self, nums: Lis

主窗口的设计与开发(二)

主窗口的设计与开发(二) 前言         在上一集当中,我们完成了主窗口的初始化,主窗口包括了左中右三个区域。我们还完成了对左窗口的初始化,左窗口包括了用户头像、会话标签页按钮、好友标签页按钮以及好友申请标签页按钮。对于切换每个标签页,我们还做了初始化信号槽的内容。最后我们将整个MainWidget类设置为单例模式。         那么这一集我们将继续完成主窗口的设计与开发,这一集我

【C++二分查找】2439. 最小化数组中的最大值

本文涉及的基础知识点 C++二分查找 LeetCode2439. 最小化数组中的最大值 给你一个下标从 0 开始的数组 nums ,它含有 n 个非负整数。 每一步操作中,你需要: 选择一个满足 1 <= i < n 的整数 i ,且 nums[i] > 0 。 将 nums[i] 减 1 。 将 nums[i - 1] 加 1 。 你可以对数组执行 任意 次上述操作,请你返回可以得到的 n

【数据结构与算法 | 灵神题单 | 删除链表篇】力扣3217, 82, 237

总结,删除链表节点问题使用到列表,哈希表,递归比较容易超时,我觉得使用计数排序比较稳,处理起来也不是很难。 1. 力扣3217:从链表中移除在数组中的节点 1.1 题目: 给你一个整数数组 nums 和一个链表的头节点 head。从链表中移除所有存在于 nums 中的节点后,返回修改后的链表的头节点。 示例 1: 输入: nums = [1,2,3], head = [1,2,3,

QtC++截图支持窗口获取

介绍 在截图工具中你会发现,接触到窗口后会自动圈出目标窗口,个别强大一点的还能进行元素识别可以自动圈出元素,那么今天简单分析一下QTc++如何获取窗口并圈出当前鼠标下的窗口。 介绍1.如何获取所有窗口2.比较函数3.实现窗口判断 结尾 1.如何获取所有窗口 1.我们需要调用windows接口EnumWindowsProc回调函数来获取所有顶级窗口,需要包含windows.

力扣 739. 每日温度【经典单调栈题目】

1. 题目 理解题意: 1.1. 给一个温度集合, 要返回一个对应长度的结果集合, 这个结果集合里面的元素 i 是 当前 i 位置的元素的下一个更高温度的元素的位置和当前 i 位置的距离之差, 若是当前元素不存在下一个更高温度的元素, 则这个位置用0代替; 2. 思路 本题用单调栈来求解;单调栈就适用于来求当前元素左边或者右边第一个比当前元素大或者小的元素;【单调栈:让栈中的元素保持单调