【滑动窗口】力扣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

相关文章

力扣SQL50 每位经理的下属员工数量 join

Problem: 1731. 每位经理的下属员工数量 👨‍🏫 参考题解 Code select m.Employee_id, m.name,count(*) reports_count,round(avg(e.age),0) average_agefrom Employees ejoin Employees mon e.reports_to = m.Employee_id

【Java算法】滑动窗口 下

​ ​    🔥个人主页: 中草药 🔥专栏:【算法工作坊】算法实战揭秘 🦌一.水果成篮 题目链接:904.水果成篮 ​ 算法原理 算法原理是使用“滑动窗口”(Sliding Window)策略,结合哈希表(Map)来高效地统计窗口内不同水果的种类数量。以下是详细分析: 初始化:创建一个空的哈希表 map 用来存储每种水果的数量,初始化左右指针 left

ScrollView 往上滑动,里面的一个View停在某个位置的思路

1.scrollView的contentoffset 为view的左上角,减去此时scrollView的左上角 2.而且还不需要让那个红色的view removeFromSuperView ,直接self.view AddSubView 就会自动从原来的那个View脱离开来 3.以后遇到问题的思路。当发现UIView很许多奇特的效果的时候,思考它是不是在不断的改变父控件。 #pragma m

算法8—不通过比较,找出两个数的最大值

问题: 比如:给定两个值 5和10,不通过比较,直接找出最大值。 分析: 一旦涉及到不用比较找最大值,想都不用想,一般只能通过位运算来实现。  max = a - ((a-b)&((a-b)>>31)) 或者 max = ((a+b)+|a-b|)/2 如果找最小值,我们只需把两个值相加,减去max即可。

Vue3的Teleport:Teleport是Vue3的一个新功能,它允许我们将子组件渲染到父组件以外的地方,这在处理模态框、弹出窗口等情况时非常有用

I. Teleport 的概述 Teleport 的定义:   在 Vue 3.0 中,Teleport 是一个新的内置组件,它允许我们将任何部分的渲染内容 Teleport(传送)到 Vue 应用范围之外的地方。 换句话说,你可以控制片段,让它们在 DOM 中的任何位置渲染,而不仅仅是在当前组件内部。   Teleport 的效用和应用场景:   Teleport 的主要用途是处理在 UI

leetcode刷题(43)——239. 滑动窗口最大值

给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回滑动窗口中的最大值。 示例: 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3输出: [3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值------------

力扣SQL50 游戏玩法分析 IV 子查询

Problem: 550. 游戏玩法分析 IV 👨‍🏫 参考题解 这个SQL查询的目的是计算每个玩家在登录后的第二天参与活动的比例。查询使用了子查询和左连接来实现这一目的。下面是查询的详细解释,包括每个部分的作用和注释: -- 计算每个玩家登录后第二天参与活动的比例select round(avg(a.event_date is not null), 2) as fractio

Android滑动回弹效果

原理: addHeaderView里做的事: 1.测量出header的宽高,调用了measureView方法 2.设置LayoutParams,宽:MATCH_PARENT,高:10 3.设置topMargin的值为负的header的高度,即将header隐藏在屏幕最上方 onInterceptTouchEvent: 如果滑动距离为零,让onInterceptTouchEvent处理。屏

Viewpager+Fragment滑动更改ListView数据和设置title文字的变化

设置ListView的数据更改只有几行代码,不用说了; 设置title的文字的变化:给ViewPager设置监听器,Viewpager变化的时候,给文字添加渐变,滑动完成后设置文字最终的大小 主要代码如下: /** * ViewPager切换监听方法 */public ViewPager.OnPageChangeListener pageListener = new ViewP

listView的item向左滑动实现删除

有一种删除功能是这样的: ListView的item向左滑动,实现删除功能 注释很清楚,简单明了 1.自定义LeftDeleteView.java继承HorizontalScrollView.java public class LeftDeleteView extends HorizontalScrollView { private int start;//开始滑动的位