LeetCode 239 滑动窗口最大值

点此看全部题解 LeetCode必刷100题:一份来自面试官的算法地图(题解持续更新中)
更多干货,请关注公众号【忍者算法】,回复【刷题清单】获取完整题解目录~

用生活中的例子来理解

想象你是一位摄影师,在拍摄一场马拉松比赛。你的相机一次只能拍摄3个跑步者(就像一个宽度为3的窗口)。随着比赛进行,你的镜头不断向前移动,每次只移动一点点,要在每张照片中找出最高的那位跑步者的身高。这就是我们今天要解决的"滑动窗口最大值"问题。

问题是什么

LeetCode第239题给我们一个任务:假设有一个数组,比如 [2,3,4,2,6,2,5,1],然后给我们一个宽度为3的窗口。这个窗口会从左往右滑动,每次移动一格。我们需要记录下每个窗口中的最大值。

举个简单的例子:

数组:[2,3,4]  窗口大小:2

第一个窗口:[2,3] 4   最大值是3
第二个窗口:2 [3,4] 最大值是4 所以最终结果是:[3,4]

最简单的解决方案:看一看比一比

就像我们肉眼看照片找最高的人一样,最简单的方法就是每次都看窗口里的所有数字,找出最大的那个。

// 这是最容易理解的方法
public int[] maxSlidingWindow(int[] nums, int k) {
int[] result = new int[nums.length - k + 1]; // 存放结果 // 对每个窗口进行处理
for (int i = 0; i <= nums.length - k; i++) {
int max = nums[i]; // 假设窗口第一个数是最大的 // 看看窗口里其他数是不是更大
for (int j = 1; j < k; j++) {
if (nums[i + j] > max) {
max = nums[i + j];
}
} result[i] = max; // 记录这个窗口的最大值
} return result;
}

这个方法很直观,就像用眼睛一个一个数字比较。但是,如果数组很长,窗口很大,这样做就会很慢。

聪明的解决方案:排队游戏

现在我们来学一个更聪明的方法。想象一个游戏:

  1. 我们有一群小朋友排队,每个小朋友手里举着一个数字牌。
  2. 我们要保证队伍里的小朋友,从前到后手里的数字是从大到小的。
  3. 当新的小朋友要进队时,就要把队伍后面所有比他数字小的小朋友请出队。
  4. 队伍最前面的小朋友,就是当前窗口的最大值。

用代码来实现这个想法:

public int[] maxSlidingWindow(int[] nums, int k) {
// 如果数组是空的,直接返回空数组
if (nums == null || nums.length == 0) return new int[0]; int[] result = new int[nums.length - k + 1]; // 存放结果
Deque<Integer> queue = new LinkedList<>(); // 这就是我们的"队伍" for (int i = 0; i < nums.length; i++) {
// 第一步:如果队伍最前面的小朋友已经不在窗口范围内了,请他离开
if (!queue.isEmpty() && queue.peek() < i - k + 1) {
queue.poll();
} // 第二步:新小朋友要入队,
// 把队尾所有比新小朋友数字小的都请出队
while (!queue.isEmpty() && nums[queue.peekLast()] < nums[i]) {
queue.pollLast();
} // 第三步:新小朋友入队
queue.offer(i); // 第四步:如果窗口已经形成,记录当前最大值
if (i >= k - 1) {
result[i - k + 1] = nums[queue.peek()];
}
} return result;
}

让我们用一个具体的例子来看这个过程:

数组:[3,1,4,2]  窗口大小:2

初始状态:队伍为空

1. 数字3来了:
队伍:[3] 2. 数字1来了:
因为1比3小,直接排在3后面
队伍:[3,1]
第一个窗口的最大值是3 3. 数字4来了:
4比1大,1离开队伍
4比3大,3离开队伍
队伍:[4]
第二个窗口的最大值是4 4. 数字2来了:
2比4小,直接排在4后面
队伍:[4,2]
第三个窗口的最大值是4

为什么这样做更好?

  1. 每个数字最多只会进队一次,出队一次
  2. 我们不用每次都看窗口里的所有数字
  3. 队伍的最前面永远是当前窗口的最大值

这就像在拍马拉松照片时,不用每次都量所有人的身高,而是保持一个有序的记录,随时知道当前画面中最高的人是谁。

小结

解决滑动窗口最大值问题,关键是要想到:

  1. 我们不需要记住窗口里的所有数
  2. 只需要保持一个"从大到小"的顺序
  3. 及时把不在窗口范围内的数字删除

这样,我们就把一个看起来很复杂的问题,变成了一个简单的"排队游戏"!


作者:忍者算法
公众号:忍者算法
c2f29413-f36f-4fc1-a443-9eabbdb400bc

从生活案例理解滑动窗口最大值:一个超直观的思路讲解|LeetCode 239 滑动窗口最大值的更多相关文章

  1. 代码随想录算法训练营day12 | leetcode 239. 滑动窗口最大值 347.前 K 个高频元素

    基础知识 ArrayDeque deque = new ArrayDeque(); /* offerFirst(E e) 在数组前面添加元素,并返回是否添加成功 offerLast(E e) 在数组后 ...

  2. Leetcode 239.滑动窗口最大值

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

  3. LeetCode(239.滑动窗口的最大值

    题目: 给定一个数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到最右侧,你只可以看到滑动窗口内的k个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 示例: 输入: nums = ...

  4. Java实现 LeetCode 239 滑动窗口最大值

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

  5. leetcode 239. 滑动窗口最大值(python)

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

  6. 【leetcode 239. 滑动窗口最大值】解题报告

    思路:滑动窗口的思想,只要是求连续子序列或者子串问题,都可用滑动窗口的思想 方法一: vector<int> maxSlidingWindow(vector<int>& ...

  7. 代码随想录第十三天 | 150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素

    第一题150. 逆波兰表达式求值 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 注意 两个整数之间的除法只保留整数部分. ...

  8. 【leetcode】239. 滑动窗口最大值

    目录 题目 题解 三种解法 "单调队列"解法 新增.获取最大值 删除 代码 题目 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以 ...

  9. 【每日一题】【双端降序队列Deque】2021年12月28日-239. 滑动窗口最大值

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

  10. 理解SetCapture、ReleaseCapture、GetCapture(控制了消息发往哪个窗口,是理解消息的关键)

    理解SetCapture.ReleaseCapture.GetCapture 正常情况下,鼠标指针位于哪个窗口区域内,鼠标消息就自动发给哪个窗口.如果调用了SetCapture,之后无论鼠标的位置在哪 ...

随机推荐

  1. golang定时器之timer+ticker

    转载: https://juejin.cn/post/7327157426298011663 Timer 是一个一次性的定时器,用于在未来的某一时刻执行一次操作. 基本使用 创建 Timer 定时器的 ...

  2. 自动化部署之Gitlab+Jenkins+Docker

    总结自动发布流程:  Gitlab+Jenkins+Docker 一般部署方式: 1.外挂方式: 就是将实际的代码挂载到宿主机上,docker中提供程序运行的环境, 这样的话只需要更新对应的代码就够了 ...

  3. 抓包工具之Fiddler(详解)

    Fiddle简介 Fiddler是最强大最好用的Web调试工具之一,它能记录所有客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数据,Fiddler包含了一个强大的基于 ...

  4. Java设计模式——职责链模式:解锁高效灵活的请求处理之道

    嘿,各位 Java 编程大神和爱好者们!今天咱们要一同深入探索一种超厉害的设计模式--职责链模式.它就像一条神奇的"处理链",能让请求在多个对象之间有条不紊地传递,直到找到最合适的 ...

  5. Winform多线程持续读取PLC数据

    1.Winform窗体界面 2.后台代码 点击查看代码 using Modbus.Device; using System; using System.Collections.Generic; usi ...

  6. tomcat部署cas6并配置自己的ssl证书

    ​配置并安装tomcat,详见我的文章:windows安装tomcat10 安装必备的软件:(在<windows安装tomcat10>中已详细配置) apache-tomcat-10.1. ...

  7. vscode+evernote印象笔记+markdown写在线笔记

    1. vscode安装evermonkey插件 2. vscode快捷键:Ctrl+Shift+P ,输入ever 按提示进行操作 Ever New: 创建新evernote笔记: 愉快地玩耍 点击下 ...

  8. 解决httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0

    httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for Se ...

  9. mysql转换类型、类型转换、查询结果类型转换

    一.问题来源 数据库一张表的主键id设为了自增,那就是int型的,但是其他表的关联字段又设置成了字符串! 而且已经开发了很久才发现问题,既然出现了问题肯定需要解决 如图 很明显id是不一样的,花了点时 ...

  10. NACOS MalformedInputException 无法读取中文配置问题

    1. 问题描述 在windows平台中打包运行springboot jar包提示如下错误 在idea中运行正常 org.yaml.snakeyaml.error.YAMLException: java ...