!!剑指 Offer 59 - I. 滑动窗口的最大值

news2025/1/27 12:31:16

剑指 Offer 59 - I. 滑动窗口的最大值
困难
632
相关企业
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。

示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:

滑动窗口的位置 最大值


[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7

提示:

你可以假设 k 总是有效的,在输入数组 不为空 的情况下,1 ≤ k ≤ nums.length。

解法一:双端队列记录的是下标,而不是值(推荐!)

参考文献:左程云《程序员代码面试指南》

思路:
申请一个双端队列,我个人的理解是,它的作用是记录各个窗口的预备最大值;
设置好这个双端队列从前端出、从后端出的规则后,队首就是当前窗口的最大值。
具体地,因为窗口的长度是固定的,不妨假设窗口的右边界i遍历数组,

先看新元素nums[i]的插入规则,
为了维持“双端队列从头到尾元素(下标)所对应的nums值严格递减”,规定“如果deque.peekLast<=nums[i],那么从后端弹出队尾元素,即deque.pollLast”,直到可以放i进双端队列deque为止;

下面介绍 过期元素(滑动窗口的老左边界)的弹出规则,
当过期元素正是双端队列的队首deque.peekFirst时,deque弹出此队首元素;
然后,如果已经形成了有效窗口(窗口长度为k),记录此次新窗口的最大值的下标,到res中。

public int[] maxSlidingWindow(int[] nums, int k) {// 我觉得这个代码更清晰、易懂
    if(nums==null||nums.length==0){return new int[0];}

    int[] res = new int[nums.length-k+1];
    int index=0;// index used by 'res'

    Deque<Integer> deque = new LinkedList<Integer>();
    for(int i=0;i<nums.length;i++){// new window is [i-w+1,...,i]
        // 清除障碍,准备加nums[i]进队列
        while(!deque.isEmpty() && nums[deque.peekLast()]<=nums[i]){// 这里可以是<,也可以是<=
            deque.pollLast();
        }
        deque.addLast(i);// 注意实际加进去的是下标,而不是值

        // [i-k,..,i-1]------>[i-k+1,i]
        // 窗口向右移动一格,老的左边界会出窗口,判断它是否是deque的队首,如果是,从头部弹出队首元素
        if(deque.peekFirst()==i-k){
            deque.pollFirst();
        }

        //record the max of this current slide window if it is formed well
        if(i>=k-1){
            res[i-k+1]=nums[deque.peekFirst()];
        }
        
    }
    return res;
}

解法二:双端队列中记录的是数值,而不是下标

此时,注意安排好“什么时候才可以从队列尾部删除元素”。
参考链接

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length==0||k==0) return new int[0];
        Deque<Integer> deque = new LinkedList<>();// deque
        int[] res = new int[nums.length-k+1];
        for(int l=1-k,r=0;r<nums.length;l++,r++){ // [l,..,r] is the current slideWindow
            if( l>0&& deque.peekFirst()==nums[l-1]){
                deque.removeFirst();                
            }
            while(!deque.isEmpty()&&deque.peekLast()<nums[r]){ // big--->small
            //注意:deque.peekLast()<nums[r] 不可以写成 deque.peekLast()<=nums[r]
            // 解释见下面的注释
                deque.removeLast();
            }
            deque.addLast(nums[r]);
            if(l>=0){
                res[l]=deque.peekFirst();
            }
        }
        
        return res;
    }
}
        
        
     

注:
有一个需要说明的地方是 while(!deque.isEmpty() && deque.peekLast() < nums[j])第二个判断必须是严格小于;否则,遇到含有重复数的测试用例时会出错。具体如:nums =[-7,-8,7,5,7,1,6,0],k=4。如果写成“deque.peekLast() <= nums[j]”,那么第二个7进双端队列会把第一个7从队尾踢出来,之后滑动窗口右端到’6’(暂时还没有加’6‘)时,会出现问题——此时,双端队列的队首元素是第二个’7‘,而滑动窗口左边界也是’7‘(是第一个7),但是根据for循环中的第一个if语句(队首元素=窗口左边界元素 成立),会让此时双端队列的队首元素(第二个’7‘)从队首弹出,然后加入’6‘,记录双端队列的队首元素为’6‘到res数组中,视为此时滑动窗口的最大值,但这显然不对——此时滑动窗口【5,7,1,6】的最大值本应该是(原数组中第二个)’7‘。元凶就是,“deque.peekLast() <= nums[j]”,这会使得第一个’7‘过早地离开双端队列,而没有料理好自己的后事,第2个’7‘做了替罪羊。

滑动窗口的应用二:构建一个能O(1)返回最大值的队列

class MaxQueue {
    LinkedList<Integer> main;
    LinkedList<Integer> sub;// big--->small

    public MaxQueue() {
        main  = new LinkedList<>();// main queue
        sub=new LinkedList<>(); // subordinate queue
    }
    
    public int max_value() {
        if(sub.isEmpty()) return -1;
        return sub.peekFirst();
    }
    
    public void push_back(int value) {
        main.addLast(value);

        while(!sub.isEmpty()&&sub.peekLast()<value){
            sub.pollLast();
        }
        sub.addLast(value);
    }
    
    public int pop_front() {
        if(main.isEmpty()) return -1;
        if(main.peekFirst().equals(sub.peekFirst())){ # !! dont use ==
            sub.pollFirst();
        }
        return main.pollFirst();

    }
}

/**
 * Your MaxQueue object will be instantiated and called as such:
 * MaxQueue obj = new MaxQueue();
 * int param_1 = obj.max_value();
 * obj.push_back(value);
 * int param_3 = obj.pop_front();
 */

值得注意的是:
在pop_front这个方法中通过 d.peekFirst() == q.peek() 判断会得到错误的结果,因为 d.peekFirst() 和 q.peek()的返回值都是Integer类型,当数值在[-128,127]这样判断是没问题的,但是超出了这个范围Integer就会为他们分别创建对象。==本质是比较两个对象的引用是否相同,故会导致明明两个方法返回值相等但是==判断为false。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/854897.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Selenium 是什么?简单明了的介绍

Selenium Selenium 是什么 Selenium 是一款 Web UI 测试工具&#xff0c;是一款 自动化测试 工具&#xff0c;使用 Selenium 测试工具进行的测试通常被称为 Selenium Testing&#xff0c;各种支持如下列表&#xff1a; UI 元素的支持与管理&#xff1a;自写代码实现浏览器支…

(八)穿越多媒体奇境:探索Streamlit的图像、音频与视频魔法

文章目录 1 前言2 st.image&#xff1a;嵌入图像内容2.1 图像展示与描述2.2 调整图像尺寸2.3 使用本地文件或URL 3 st.audio&#xff1a;嵌入音频内容3.1 播放音频文件3.2 生成音频数据播放 4 st.video&#xff1a;嵌入视频内容4.1 播放视频文件4.2 嵌入在线视频 5 结语&#x…

c语言每日一练(4)

五道选择题 1、有以下代码&#xff0c;程序的输出结果是( ) #include <stdio.h> int main() {int a 0, b 0;for (a 1, b 1; a < 100; a){if (b > 20) break;//1if (b % 3 1)//2{b b 3;continue;}b b-5;//3}printf("%d\n", a);return 0; } A.1…

JavaWeb(11)——前端综合案例5(小黑记事本)

一、实例需求 ⌛ 功能需求&#xff1a; ① 列表渲染 ② 删除功能 ③ 添加功能 ④ 底部统计 和 清空任务 二、代码实现 ☕ <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8" /> <meta http-equiv"X-UA-Compa…

intelJ IDEA\PHPStorm \WebStorm\PyCharm 通过ssh连接远程Mysql\Postgresql等数据库

最容易出错的地方是在general面板下的host&#xff0c;不应该填真实的host地址&#xff0c;而应该填localhost或者127.0.0.1 具体操作步骤见下图

swagger 3.0 学习笔记

引入pom <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency>配置 import io.swagger.models.auth.In; import io.swagger.v3.oas.annotati…

SpringBoot Thymeleaf模板引擎

Thymeleaf 模板引擎 前端交给我们的页面&#xff0c;是html页面。如果是我们以前开发&#xff0c;我们需要把他们转成jsp页面&#xff0c;jsp好处就是当我们查出一些数据转发到JSP页面以后&#xff0c;我们可以用jsp轻松实现数据的显示&#xff0c;及交互等。 jsp支持非常强大…

1077 Kuchiguse

PTA | 程序设计类实验辅助教学平台 一个测试点没过&#xff0c;不知道哪的原因 #include<bits/stdc.h> using namespace std; const int N210; int n; string s[N]; string str[N]; string ans; int main() {int len300;scanf("%d",&n);getchar();for(int…

[C初阶笔记]P1

什么是C语言 1、机器语言&#xff08;二进制&#xff09;>汇编语言&#xff08;助记符&#xff09;>高级语言&#xff08;C、C等&#xff09; 2、c语言擅长底层软件开发&#xff08;操作系统、驱动程序&#xff09;&#xff0c;并不意味着不能开发其他。 C语言更贴近操作…

linux挂载sd卡

1、确定设备名&#xff1a;打开终端窗口&#xff0c;运行以下命令来查看已连接的存储设备列表 rootws:/# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTmmcblk1 179:0 0 7.3G 0 disk |-mmcblk1p1 179:1 0 70M 0 part -mmcblk1p2 179:2 0…

用datagrip远程连接mysql超时怎么解决【连接mysql会遇到的坑】

目录 一.开放端口 【1】在linux打开防火墙或开放3306端口&#xff08;其实一般情况下服务器里的防火墙并没有开启&#xff09;​编辑 【2】在控制台的云安全组里开放端口 二.修改datagrip连接时高级的useSSL属性 先填好主机&#xff08;就是IP地址&#xff09;和端口&#…

ProComponent 用法学习

相信很多同学都用过 Ant Design 这一 react 著名组件库&#xff0c;而 ProComponents 则是在 antd 之上进行封装的页面级组件库&#xff08;指一个组件就可以搞定一个页面&#xff09;。它同时也是 Ant Design Pro 中后台框架所用的主要组件库。如果你手上有要用 react 开发的中…

Pytorch深度学习-----现有网络模型的使用及修改(VGG16模型)

系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用&#xff08;ToTensor&#xff0c;Normalize&#xff0c;Resize &#xff0c;Co…

photoshop PS 查看像素坐标、像素颜色、像素HSB颜色

方法一 photoshop 菜单栏 窗口菜单->信息菜单项(F8), 在信息窗口里会有当前的 x&#xff0c;y坐标 方法二 photoshop 菜单栏 视图菜单->标尺菜单项&#xff08;ctrlR&#xff09; 宽度和高度边上都有标尺&#xff0c;默认的是厘米&#xff0c;右键单机宽度和高度边上…

【自动化测试框架】关于unitttest你需要知道的事

一、UnitTest单元测试框架提供了那些功能 1.提供用例组织和执行 如何定义一条“测试用例”? 如何灵活地控制这些“测试用例”的执行? 2.提供丰定的断言方法 当测试用例的执行结果与预期结果不一致时&#xff0c;判定测试用例失败。在自动化测试中&#xff0c;通过“断言”…

【IMX6ULL驱动开发学习】04.应用程序和驱动程序数据传输和交互的4种方式:非阻塞、阻塞、POLL、异步通知

一、数据传输 1.1 APP和驱动 APP和驱动之间的数据访问是不能通过直接访问对方的内存地址来操作的&#xff0c;这里涉及Linux系统中的MMU&#xff08;内存管理单元&#xff09;。在驱动程序中通过这两个函数来获得APP和传给APP数据&#xff1a; copy_to_usercopy_from_user …

MySQL之深入InnoDB存储引擎——Undo页

文章目录 一、UNDO日志格式1、INSERT操作对应的UNDO日志2、DELETE操作对应的undo日志3、UPDATE操作对应的undo日志1&#xff09;不更新主键2&#xff09;更新主键的操作 3、增删改操作对二级索引的影响 二、UNDO页三、UNDO页面链表四、undo日志具体写入过程五、回滚段1、回滚段…

Java课题笔记~ Servlet编程

1.Servlet编程基础 (1)什么是Servlet Servlet是基于Java语言的Web编程技术&#xff0c;部署在服务器端的Web容器里&#xff0c;获取客户端的访问请求&#xff0c;并根据请求生成响应信息返回给客户端。 创建Servlet的方式&#xff0c;有 如下图&#xff1a;一般创建Servlet都…

Vue3 表单输入绑定简单应用

去官网学习→表单输入绑定 | Vue.js 运行示例&#xff1a; 代码&#xff1a;HelloWorld.vue <template><div class"hello"><h1>Vue 表单输入绑定</h1><input type"text" placeholder"输入框" v-model"msg"…

Open_PN笔记

>>>仅用作学习用途 1.准备好需要用到的工具 官网下载地址&#xff1a; openvpn 客户端下载地址&#xff1a; https://swupdate.openvpn.org/community/releases/openvpn-install-2.4.5-I601.exe EasyRSA下载地址&#xff1a; https://githu…