【LeetCode】剑指 Offer Ⅱ 第7章:队列(6道题) -- Java Version

news2024/10/6 16:16:24

题库链接:https://leetcode.cn/problem-list/e8X3pBZi/

在这里插入图片描述

类型题目解决方案
滑动窗口剑指 Offer II 041. 滑动窗口的平均值队列:滑动窗口 ⭐
剑指 Offer II 042. 最近请求次数队列:滑动窗口 ⭐
二叉树宽搜剑指 Offer II 043. 在完全二叉树中添加节点BFS(宽搜):完全二叉树 ⭐
剑指 Offer II 044. 二叉树中每层的最大值双队列:按层顺序宽搜 ⭐
剑指 Offer II 045. 二叉树最低层最左边的值双队列:按层顺序宽搜 ⭐
剑指 Offer II 046. 二叉树的右视图双队列:按层顺序宽搜 ⭐

队列:先入先出,因此新的元素只能添加到队列的尾部,同时只能删除位于队列最前面的元素;
Java 中 Queue 的常用操作:

  • add(e) / offer(e):插入元素;
  • remove() / poll():删除元素;
  • element() / peek():返回最前面的元素;

……
在 Java 中实现接口 Queue 的常用类型有:LinkedList、ArrayDeque 以及 PriorityQueue,但 PriorityQueue 并不是真正的队列,而是堆。


1. 剑指 Offer II 041. 滑动窗口的平均值 – P111

给定一个窗口大小和一个整数数据流,根据该滑动窗口的大小,计算滑动窗口里所有数字的平均值。
实现 MovingAverage 类:

  • MovingAverage(int size) 用窗口大小 size 初始化对象。
  • double next(int val) 成员函数 next 每次调用的时候都会往滑动窗口增加一个整数,请计算并返回数据流中最后 size 个值的移动平均值,即滑动窗口里所有数字的平均值。

1.1 队列:滑动窗口 – O(1)(⭐)

时间复杂度 O ( 1 ) O(1) O(1),空间复杂度 O ( n ) O(n) O(n)

PS:常见实现滑动窗口的方法除了队列之外,还可以实现数组 + 双指针的方式实现,相关内容可参考:【LeetCode】剑指 Offer Ⅱ 第2章:数组(8道题) – Java Version

class MovingAverage {

    ArrayDeque<Integer> deque;  // 队列
    int capicity;  // 容量大小
    int sum;  // 滑动窗口累加和

    /** Initialize your data structure here. */
    public MovingAverage(int size) {
        deque = new ArrayDeque<>();
        capicity = size;
        sum = 0;
    }
    
    public double next(int val) {
        if (deque.size() >= capicity) {  // 窗口已满,删除一个再加入一个
            int val2 = deque.poll();
            deque.offer(val);
            sum += val - val2; 
        } else {
            deque.offer(val);  // 窗口未满,直接加入
            sum += val;
        }
        return (double) sum / deque.size();  // 计算当前平均数
    }
}
/**
 * Your MovingAverage object will be instantiated and called as such:
 * MovingAverage obj = new MovingAverage(size);
 * double param_1 = obj.next(val);
 */

在这里插入图片描述

2. 剑指 Offer II 042. 最近请求次数 – P112

写一个 RecentCounter 类来计算特定时间范围内最近的请求。
请实现 RecentCounter 类:

  • RecentCounter() 初始化计数器,请求数为 0 。
  • int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。

保证 每次对 ping 的调用都使用比之前更大的 t 值。

2.1 队列:滑动窗口 – O(1)(⭐)

时间复杂度 O ( 1 ) O(1) O(1),空间复杂度 O ( n ) O(n) O(n)

class RecentCounter {
    ArrayDeque<Integer> deque;
    int windowSize;

    public RecentCounter() {
        deque = new ArrayDeque<>();
        windowSize = 3000;  // 3000ms
    }
    
    public int ping(int t) {    
        deque.offer(t);  // 来就加入
        while (deque.peek() + windowSize < t) {  // 划出范围就出队
            deque.poll();
        }
        return deque.size();
    }
}
/**
 * Your RecentCounter object will be instantiated and called as such:
 * RecentCounter obj = new RecentCounter();
 * int param_1 = obj.ping(t);
 */

在这里插入图片描述

3. 剑指 Offer II 043. 在完全二叉树中添加节点 – P115

完全二叉树是每一层(除最后一层外)都是完全填充(即,节点数达到最大,第 n 层有 2n-1 个节点)的,并且所有的节点都尽可能地集中在左侧。
设计一个用完全二叉树初始化的数据结构 CBTInserter,它支持以下几种操作:

  • CBTInserter(TreeNode root) 使用根节点为 root 的给定树初始化该数据结构;
  • CBTInserter.insert(int v) 向树中插入一个新节点,节点类型为 TreeNode,值为 v 。使树保持完全二叉树的状态,并返回插入的新节点的父节点的值;
  • CBTInserter.get_root() 将返回树的根节点。

3.1 BFS(宽搜):完全二叉树 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

Key:二叉树的广度优先搜索是从上到下按层遍历二叉树,从二叉树的根节点开始,先遍历二叉树的第1层,再遍历第2层,接着遍历第3层,并以此类推。(通常我们会基于队列来实现二叉树的广度优先搜索)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class CBTInserter {
    ArrayDeque<TreeNode> deque;
    TreeNode root;  // 根节点

    public CBTInserter(TreeNode root) {  // 初始化
        deque = new ArrayDeque<>();
        this.root = root;
        deque.offer(root);
        // 将满状态的节点弹出,并使其孩子节点入队
        while (deque.peek().left != null && deque.peek().right != null) {
            TreeNode node = deque.poll();
            deque.offer(node.left);
            deque.offer(node.right);
        }
    }
    
    public int insert(int v) {  // 插入新节点,并返回新节点的父节点
        TreeNode parent = deque.peek();
        TreeNode node = new TreeNode(v);
        if (parent.left == null) {
            parent.left = node;
        } else if (parent.right == null) {
            parent.right = node;
            deque.poll();  // 弹出已满的父节点,并将其孩子节点入队
            deque.offer(parent.left);
            deque.offer(parent.right);
        }
        return parent.val;
    }
    
    public TreeNode get_root() {  // 返回根节点
        return this.root;
    }
}

/**
 * Your CBTInserter object will be instantiated and called as such:
 * CBTInserter obj = new CBTInserter(root);
 * int param_1 = obj.insert(v);
 * TreeNode param_2 = obj.get_root();
 */

在这里插入图片描述

4. 剑指 Offer II 044. 二叉树中每层的最大值 – P119

给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

在这里插入图片描述

4.1 双队列:按层顺序宽搜 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

Key:如果用广度优先的顺序遍历二叉树时需要区分二叉树的每层,就推荐采用双队列的形式实现:用两个不同的队列 queue1queue2 分别存放两层的节点,队列 queue1 中只存放当前遍历层的节点,而队列 queue1 中只放下一层的节点。(当然,除此之外,我们也可以使用单队列 + 计数器 current | next 的形式来实现同样的效果)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> largestValues(TreeNode root) {
        ArrayDeque<TreeNode> deque1 = new ArrayDeque<>();
        ArrayDeque<TreeNode> deque2 = new ArrayDeque<>();
        int max = Integer.MIN_VALUE;
        List<Integer> res = new ArrayList<>();

        if (root != null) {
            deque1.offer(root);
        }

        while (!deque1.isEmpty()) {
            TreeNode node = deque1.poll();
            max = Math.max(max, node.val);

            if (node.left != null) {
                deque2.offer(node.left);
            }

            if (node.right != null) {
                deque2.offer(node.right);
            }

            if (deque1.isEmpty()) {
                res.add(max);  // 将当前层的最大值保存到结果集
                max = Integer.MIN_VALUE;  // 初始化max
                deque1 = deque2;  // 让 q1 指向 q2
                deque2 = new ArrayDeque<>();
            }
        }
        return res;
    }
}

5. 剑指 Offer II 045. 二叉树最低层最左边的值 – P122

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。

5.1 双队列:按层顺序宽搜 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

Key,解法基本同上一题,不同的是上一题找的是每层的最大值,本题找的是最低层的最左值,也可以扩展为每层的最左值。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int findBottomLeftValue(TreeNode root) {
        ArrayDeque<TreeNode> deque1 = new ArrayDeque<>();  // 保存当前遍历层的节点
        ArrayDeque<TreeNode> deque2 = new ArrayDeque<>();  // 保存下一层的节点
        deque1.offer(root);  // 加入根节点
        int bottomLeft = root.val;

        while (!deque1.isEmpty()) {
            TreeNode node = deque1.poll();

            if (node.left != null) {
                deque2.offer(node.left);
            }

            if (node.right != null) {
                deque2.offer(node.right);
            }

            if (deque1.isEmpty()) {  // 当前层遍历完毕
                deque1 = deque2;
                deque2 = new ArrayDeque<>();
                if (!deque1.isEmpty()) {
                    bottomLeft = deque1.peek().val;
                }
            }
        }
        return bottomLeft;
    }
}

在这里插入图片描述

6. 剑指 Offer II 046. 二叉树的右视图 – P123

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

在这里插入图片描述

6.1 双队列:按层顺序宽搜 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

Key:本题查找的是每层的最右节点

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        if (root == null) return new ArrayList<>();

        ArrayDeque<TreeNode> dq1 = new ArrayDeque<>();
        ArrayDeque<TreeNode> dq2 = new ArrayDeque<>();

        dq1.offer(root);
        List<Integer> list = new ArrayList<>();

        while (!dq1.isEmpty()) {
            TreeNode node = dq1.poll();

            if (node.left != null) {
                dq2.offer(node.left);
            }

            if (node.right != null) {
                dq2.offer(node.right);
            }

            if (dq1.isEmpty()) {  // 此时当前层已经遍历完毕,node即为最右节点
                list.add(node.val);
                dq1 = dq2;
                dq2 = new ArrayDeque<>();
            } 
        }
        return list;
    }
}

在这里插入图片描述

7. 继续提升:加练题目

🎈 可参考:

  • 队列 · SharingSource/LogicStack-LeetCode Wiki · GitHub
  • 单调队列 · SharingSource/LogicStack-LeetCode Wiki · GitHub

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

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

相关文章

【软件设计师-从小白到大牛】上午题基础篇:第七章 程序设计语言与语言处理程序基础

文章目录 前言章节提要一、编译过程真题链接解释器与编译器特点与区别真题链接 二、文法的定义以及语法推导树真题链接 三、有限自动机与正规式四、表达式真题链接 五、函数调用&#xff08;传值与传址&#xff09;传值调用与传址调用真题链接 六、各种程序语言的特点真题链接 …

ubuntu下yolov7 tensorrt模型部署

文章目录 ubuntu下yolov7 tensorrt模型部署一、Ubuntu18.04环境配置1.1 安装工具链和opencv1.2 安装Nvidia相关库1.2.1 安装Nvidia显卡驱动1.2.2 安装 cuda11.31.2.3 安装 cudnn8.21.2.4 下载 tensorrt8.4.2.41.2.5 下载仓库TensorRT-Alpha并设置 二、从yolov7源码中导出onnx文…

【招招制敌】修改element-ui中el-image 预览图大小的默认尺寸,让展示效果更加有呼吸感

【招招制敌】修改element-ui中el-image 预览图大小的默认尺寸&#xff0c;让展示效果更加有呼吸感 1、问题&#xff08;需求&#xff09;2、解决2.1 深度修改不起效2.2 修改全局样式 3、效果 1、问题&#xff08;需求&#xff09; 在未修改前&#xff0c;el-image 预览图大小的…

Element学习使用

引入: npm方式: npm i element-ui -S 或: cnpm install element-ui --save 要先整合cnpm 在项目中引入: 1.main.js import element-ui/lib/theme-chalk/index.css; import ElementUI from element-ui;Vue.use(ElementUI)引入网址组件方式: <!-- 引入样式 --> <lin…

AI智能助理系统在线提问系统 轻松解答,快速解决问题

今天给大家分享一款AI智能助理系统在线提问系统&#xff0c;也就是人工智能对话系统&#xff0c;&#xff0c;它可以陪你聊天&#xff0c;帮你写文章&#xff0c;帮你写论文&#xff0c;帮你写代码&#xff0c;帮你写小说&#xff0c;帮你创意策划&#xff0c;帮你做Excel表格&…

联合和枚举!!详解

目录 1. 1联合体类型的声明 1.2. 联合体的特点 1.3. 联合体⼤⼩的计算 1.4联合体有什么用&#xff1f; 1.5用联合体判断机器大小端。 2.1枚举类型 2.1.1枚举类型的声明 2.2枚举类型的优点 1. 1联合体类型的声明 和结构体类似&#xff0c;联合体也由成员变量组成&#x…

《UnityShader入门精要》学习4

一个最简单的顶点/片元着色器 一个最简单的顶点/片元着色器 Unity Shader的基本结构。它包含了Shader、Properties、SubShader、Fallback等语义块。顶点/片元着色器的结构与之大体类似 Shader "MyShaderName" {Properties {// 属性}SubShader {// 针对显卡A的S…

安全隐患随手拍小程序搭建-人人都是安全员活动

各生产型企业都会组织开展“安全隐患随手拍”活动&#xff0c;目的就是使广大职工积极发现身边的安全隐患&#xff0c;从而提高自身安全意识&#xff0c;重视安全生产&#xff0c;营造“人人查安全、人人保安全”的良好氛围。 可传统靠微信群组或QQ邮箱上报隐患方式&#xff0c…

Linux服务器快速搭建pytorch

Linux服务器搭建pytorch 文章目录 Linux服务器搭建pytorch一、使用FileZilla传输Anaconda二、激活Anaconda环境1.创建一个虚拟环境2.使用已有项目生成requirements.txt3.在虚拟环境中使用requirements.txt安装其他项目相关库 总结 一、使用FileZilla传输Anaconda 提示&#xf…

微信小程序获取当前日期时间

一、直接使用方式 在小程序中获取当前系统日期和时间&#xff0c;可直接拿来使用的常用的日期格式 //1. 当前日期 YYYY-MM-DDnew Date().toISOString().substring(0, 10)new Date().toJSON().substring(0, 10)//2. 当前日期 YYYY/MM/DDnew Date().toLocaleDateString()//3.…

计算机图形学(有效边表算法)用知识,改变命运的秘密【Morty深度干货】视频学习

目录 1.你所身处的世界&#xff0c;其实并非是一个真实的世界 3、哪些知识&#xff0c;会真正影响到我们的人生 你要用大量的精力去学习对于你的人生能产生实际价值的领域的知识 历史 经济学 金融与投资 心理学 永远不要去相信人&#xff0c;而是要去相信人性 成长的路…

2023年中国禽流感疫苗产量、需求量及市场规模分析[图]

禽流感疫苗是以甲型流行性感冒病毒H5N1、H9N2等毒株经处理后制备的灭活疫苗。用于预防人感染高致病性禽流感病毒感染&#xff0c;控制禽流感的流行。 从产业链来看&#xff0c;禽流感疫苗行业上游为原材料市场&#xff0c;主要有非免蛋、血清、佐剂等。禽流感疫苗行业下游主要为…

博客系统(java,MySQL,HTML)

项目展示&#xff1a; 1.输入 http://127.0.0.1:8080/blog_system/login.html 即可进入登录页面 2.输入正确的用户名和密码后进入博客列表页 要是用户名或密码输入错误&#xff0c;会弹出错误提示框 3.点击查看全文&#xff0c;可以进入博客详情页查看详细信息 4.点击写博客&a…

Studio One6.5中文版本下载安装步骤

在唱歌效果调试当中&#xff0c;我们经常给客户安装的几款音频工作站。第一&#xff0c;Studio One 6是PreSonus公司开发的一款功能强大的音频工作平台&#xff0c;具有丰富的音频处理功能和灵活的工作流程。以下是Studio One6的一些主要特点&#xff1a; 1.多轨录音和编辑&…

树模型(三)决策树

决策树是什么&#xff1f;决策树(decision tree)是一种基本的分类与回归方法。 长方形代表判断模块 (decision block)&#xff0c;椭圆形成代表终止模块(terminating block)&#xff0c;表示已经得出结论&#xff0c;可以终止运行。从判断模块引出的左右箭头称作为分支(branch)…

lc42接雨水详解

1 42. 接雨水 接雨水 2 推荐阅读的解析 《接雨水》详细通俗的思路分析&#xff0c;多解法 推荐观看方法&#xff1a;二、三和四 3 不懂的地方-方法四的一个判断条件 以下是疑问的地方 height [ left - 1] 是可能成为 max_left 的变量&#xff0c; 同理&#xff0c;height…

隧道代理-

文章目录 代理代理使用场景VPS建立隧道frpMSF木马生成监听开启frp服务端和客户端执行exe木马文件 代理 实验环境&#xff1a; 攻击机kali&#xff1a;192.168.160.32&#xff08;NAT模式&#xff09;模拟的公网服务器&#xff08;本机&#xff09;&#xff1a;10.9.75.214失陷…

SQL Server远程登录失败

SQL Server远程登录失败 检查SQL SERVER 是否允许远程访问. 具体步骤: 1)在远端SQL Server主机上,打开SSMS并连接数据库 2)在相应”数据库”上单击右键,选择”属性” 3)选择”连接”选项卡,检查”远程服务器连接”下,RPC服务是否选择. 设置SQL Server相关TCP连接 1.打开SQL Se…

代码随想录算法训练营第天十六天丨 二叉树part04

文档讲解&#xff1a;代码随想录 状态&#xff1a;已完成 513.找树左下角的值 思路 递归 分析一下题目&#xff1a;在树的最后一行找到最左边的值。 首先要是最后一行&#xff0c;然后是最左边的值。 如果使用递归法&#xff0c;如何判断是最后一行呢&#xff0c;其实就是…

为数据列表的每条记录生成对应的二维码

效果图&#xff1a; 一、前端 <!DOCTYPE html> <html lang"zh" xmlns:th"http://www.thymeleaf.org" xmlns:shiro"http://www.pollix.at/thymeleaf/shiro"> <head><th:block th:include"include :: header(固定资产…