LeetCode第239题:滑动窗口k内求最大值

server/2024/10/17 21:36:29/

来源:LeetCode第239题
难度:困难

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
这段代码实现了 滑动窗口最大值 的问题,使用了 双端队列(deque)来高效地找到数组 nums 中每个大小为 k 的滑动窗口的最大值。以下是代码的详细解析:

代码概述

public int[] maxSlidingWindow(int[] nums, int k) {int index = 0, len = nums.length;int[] ans = new int[len - k + 1];// 双端队列,存储元素的下标Deque<Integer> deque = new ArrayDeque<>();for (int i = 0; i < len; i++) {// 如果队列中队头元素和当前元素位置相差i-k,相当于队头元素要出窗口了,就把队头元素给移除。if (!deque.isEmpty() && deque.peekFirst() <= i - k)deque.pollFirst();// 在添加一个值之前,前面比他小的都要被移除掉,并且还要保证窗口中队列头部元素永远是队列中最大的。while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i])deque.pollLast();deque.addLast(i); // 当前元素的下标加入到队列的尾部。// 当窗口的长度大于等于k个的时候才开始计算(注意这里的i是从0开始的)。if (i >= k - 1)// 队头元素是队列中最大的,把队列头部的元素加入到数组中。ans[index++] = nums[deque.peekFirst()];}return ans;
}

详细解析

初始化:

int index = 0: 用于跟踪结果数组 ans 中下一个最大值要存储的位置。
int len = nums.length: nums 数组的长度。
int[] ans = new int[len - k + 1]: 结果数组,用于存储每个滑动窗口的最大值。大小为 len - k + 1,因为数组中有这么多大小为 k 的窗口。
Deque deque = new ArrayDeque<>(): 创建一个双端队列,用于存储数组元素的下标。
遍历数组:

for (int i = 0; i < len; i++): 遍历每一个元素。
移除超出窗口的下标:

if (!deque.isEmpty() && deque.peekFirst() <= i - k): 检查队列的队头(最大值的下标)是否超出了当前窗口的范围。如果超出,移除队头元素。
维护队列中的最大值:

while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]): 当当前元素 nums[i] 大于队列中对应的元素时,移除队列末尾的下标。这确保队列中的下标对应的元素是当前窗口中的潜在最大值。
deque.addLast(i): 将当前元素的下标 i 加入到队列的末尾。
记录最大值:

if (i >= k - 1): 判断当前索引 i 是否到达第一个有效窗口的结束(即 i 至少为 k - 1)。
ans[index++] = nums[deque.peekFirst()]: 将队列头部的元素(即当前窗口的最大值)存储到结果数组 ans 中。
返回结果:

return ans;: 返回包含每个滑动窗口最大值的数组。
时间复杂度
算法的时间复杂度为 O(n),其中 n 是 nums 数组的元素数量。每个元素最多被加入和移除队列一次,使得算法在处理大输入时非常高效。
空间复杂度
空间复杂度为 O(k),因为在最坏情况下,队列最多可以存储 k 个下标。
示例
假设 nums = [1, 3, -1, -3, 5, 3, 6, 7] 且 k = 3:

滑动窗口的最大值如下:
窗口 1: [1, 3, -1] -> 最大值 = 3
窗口 2: [3, -1, -3] -> 最大值 = 3
窗口 3: [-1, -3, 5] -> 最大值 = 5
窗口 4: [-3, 5, 3] -> 最大值 = 5
窗口 5: [5, 3, 6] -> 最大值 = 6
窗口 6: [3, 6, 7] -> 最大值 = 7
最终的输出将是 [3, 3, 5, 5, 6, 7]。

这种方法既高效又清晰,利用双端队列有效地维护滑动窗口中的最大值。


http://www.ppmy.cn/server/132585.html

相关文章

Android常用界面控件——ImageView

目录 1 ImageView 1.1在XML 中定义ImageView&#xff1a; 1.1.1 ImageView常用XML属性 1.1.2 ImageView ScaleType用法 1.2 在Java代码中控制ProgressBar&#xff1a; 1.3 区别总结 1.3.1 应用场景选择建议 1 ImageView ImageView&#xff0c;图像视图&#xff0c;直接…

群晖前面加了雷池社区版,安装失败,然后无法识别出用户真实访问IP

有nas的相信对公网都不模式&#xff0c;在现在基础上传带宽能有100兆的时代&#xff0c;有公网代表着家里有一个小服务器&#xff0c;像百度网盘&#xff0c;优酷这种在线服务都能部署为私有化服务。但现在运营商几乎不可能提供公网ip&#xff0c;要么自己买个云服务器做内网穿…

五个必备的高清无水印视频素材库推荐

做抖音、短视频创作的朋友都知道&#xff0c;优质的素材往往决定了作品能否获得更多关注。如果你还不知道在哪里下载高清无水印的视频素材&#xff0c;不用担心&#xff01;今天为你推荐5个高品质的视频素材库&#xff0c;助你轻松创作出爆款视频。 蛙学网 是国内领先的视频素材…

为什么barrier连接成功鼠标却过不去

关于barrier的下载、安装和配置方法网上有很多&#xff0c;当然也可以参考我的这篇文章&#xff1a;使用barrier将window和ubuntu共用键鼠的方法 正常情况下是能配置并且连接成功&#xff0c;今天重装系统重新配置barrier后发现虽然连接成功&#xff0c;但键鼠还是无法工用一套…

java 利用mpxj解析MPP及结合jacob导出MPP

导出mpp需要提前配置 到jacob官网去下载对应的jacob-1.21.zip&#xff0c;获取去jacob github下载&#xff0c;下载后进行解压会有以下文件&#xff1a; 其中需要将jacob-1.21-x64.dll及jacob-1.21-x86.dll文件放到jdk安装目录下的bin目录下&#xff1a; 此处便配置好了导出mp…

C、C++常用数据结构:顺序表

前言&#xff1a;线性表 讲顺序表之前先讲讲线性表。 线性表&#xff1a;种数据结构&#xff0c;用来表示具有相同类型的有限个数据元素的集合。线性表的性质&#xff1a; 有序性&#xff1a;线性表中的数据元素是按一定顺序排列的&#xff0c;每个元素都有确定的位置唯一性&…

【论文阅读】OWKRL:2024年的视觉推理任务不用VLMs还可以怎么做

目录 写在前面1. 动机与贡献1.1 动机1.2 贡献 2. 开放世界知识表示学习方法&#xff08;OWKRL&#xff09;2.1 问题定义2.2 知识三元组表示获取2.2.1 基于图的 Self-cross Transformer2.2.2 头实体提取2.2.3 尾实体提取2.2.4 关系提取 2.3 知识表示学习2.3.1 开放世界表示学习2…

github下载文件的两种方式(非git形式)

1.以下面的图为例 &#xff0c;可以直接点击右上方的绿色Code按键&#xff0c;在弹出的列表中选择Download Zip选项&#xff0c;即可下载。 2.如果下载的是单独的某一个文件&#xff0c;则可以按照下图的格式点击下图所示的那个下载的图标即可。