2024收尾工作
目录
开场白
栈与队列
LeetCode232. 用栈实现队列
LeetCode225. 用队列实现栈
LeetCode102. 二叉树的层序遍历
LeetCode103. 二叉树的锯齿形层序遍历
堆(优先级队列)
堆排序
LeetCode215. 数组中的第 k 个最大元素
总结
开场白
今天是除夕,在此首先祝各位读者朋友们新年快乐!愿你在新的一年里,心怀希望,勇敢追梦,愿每一天都充满温暖与惊喜,愿所有的努力都能开花结果,所有的期待都能如愿以偿。
从寒假开始,为了准备面试,我在我的个人CSDN账号陆续发布了Java实现数据结构与算法的相关文章,意在从我个人角度深度理解数据结构。将相关文章分享分布后,很多读者通过私信方式与我交流讨论,每次看到大家的留言,无论是鼓励、建议,还是探讨问题,都让我倍感温暖,也让我更加坚定了继续分享知识的决心。各位读者的支持是我持续创作的最大动力。
言归正传,我们今天简要分析前几篇文章中涉及到的数据结构在 中的应用。很多数据结构在实际问题中是结合着使用的,例如二叉树的层序遍历需要使用到队列作为辅助,因为层序遍历实际上是一种广度优先搜索(Breadth First Search,BFS),二叉树的前中后序遍历的迭代方式的实现需要使用到栈,即使在递归实现中我们使用三行代码可以实现需求,但是递归函数底层使用了函数调用栈,如果使用迭代方式,我们就需要使用栈来模拟函数调用栈的行为。
栈与队列
LeetCode232. 用栈实现队列
232. 用栈实现队列 - 力扣(LeetCode)
本题要求使用两个栈来模拟一个队列,此队列应该支持常见的入队、出队、获取队首元素以及判空几个常见操作。
这个题让我的思绪回到了大一考学院实验室的时候,当时过了笔试环节,面试环节一个学长很突然的问了我这个问题——“如何用两个栈模拟一个队列”,当时一紧张,说成了两栈共享空间,学长说 “不好意思,我没太明白你的意思”。
实际上只要了解了队列和栈的特性,解决这个问题就很容易了。我们需要定义两个栈,分别是输入栈和输出栈,前者用于接收入队元素,后者用于处理获取队首元素和出队操作。假设我们连续向队列中入队元素,我们直接将这些元素按顺序压入输入栈,此时输入栈就保存了所有入队元素,栈顶元素就是队尾元素,如果我们需要执行出队或获取队首元素操作,我们需要将输入栈的所有元素按顺序出栈,然后重新压入到输出栈,那么此时输出栈的栈顶元素就变成了模拟队列的队首元素,执行出队操作就是将输出栈的栈顶元素出栈,获取队首元素就是获取输出栈的栈顶元素。如果后续还需要入队元素,直接将元素压入输入栈,如果需要获取队首元素或者出队,先判断一下输出栈是否为空,如果输出栈为空,就需要执行相同的操作将输入栈的元素按顺序入栈到输出栈,此时栈顶元素就是队首元素。实现代码如下。
class MyQueue {private final ArrayStack<Integer> inputStack;private final ArrayStack<Integer> outputStack;private int size;public MyQueue() {inputStack = new ArrayStack<>(101);outputStack = new ArrayStack<>(101);size = 0;}public void push(int x) {inputStack.push(x);size++;}public int pop() {if (outputStack.isEmpty())while (!inputStack.isEmpty())outputStack.push(inputStack.pop());size--;return outputStack.pop();}public int peek() {if (outputStack.isEmpty())while (!inputStack.isEmpty())outputStack.push(inputStack.pop());return outputStack.peek();}public boolean empty() {return size == 0;}
}
在以上实现中,我们在类 中定义了一个用于表示模拟队列存储元素数量的变量
,通过此方式在后续实现
方法时就很容易,直接判断
是否为
即可,我们也可以通过判断两栈是否同时为空得出队列是否为空。
需要提前指出的是,我们这里使用了顺序栈,在构造顺序栈时需要传入期望规模参数 ,本题已经说明,入队出队操作不会超过
次,我们直接规定顺序栈的期望规模为
,这样就不需要执行判满判空等操作。再次提醒,提交代码时需要将自定义的顺序栈类
同时提交。当然,我们也可以使用
类来实现栈。
LeetCode225. 用队列实现栈
225. 用队列实现栈 - 力扣(LeetCode)
本题需要使用两个队列模拟栈的操作,模拟栈需要支持普通栈的入栈、出栈、获取栈顶元素和判空操作。我们知道,队列是一种先入先出FIFO数据结构,而栈是一种后入先出LIFO数据结构,如果按照顺序将元素入队,那么队首一定是模拟栈的栈底元素,而队尾一定是模拟栈的栈顶元素。所以使用队列模拟栈的时候,我们可以直接让元素序列入队到第一个队列,在出栈或获取栈顶元素时,让队尾之前的所有元素出队,并让这些元素按刚才出队的顺序入队到另一个队列,这个队列的作用就是暂存模拟栈栈顶元素的所有后继元素,如果是出栈操作,将第一个队列剩余的最后一个元素出队并用变量接收返回即可,然后将第二个队列的所有元素出队,让这些元素按照顺序重新入队到第一个队列;如果只是单纯获取栈顶元素,我们在拿到第一个队列剩余的最后一个元素后,第二个队列的所有元素出队,让这些元素按照出队顺序重新入队到第一个队列。方便起见,我们可以自定义一个用于表示模拟栈中存储元素数量的变量 ,所以实现判空操作就很简单了,直接判断
是否为
即可。代码如下。
class MyStack {private final ArrayQueue<Integer> queue1;private final ArrayQueue<Integer> queue2;private int size;public MyStack() {queue1 = new ArrayQueue<>(101);queue2 = new ArrayQueue<>(101);size = 0;}public void push(int x) {queue1.offer(x);size++;}public int pop() {int temp = size;while (temp -- != 1)queue2.offer(queue1.pull());Integer ans = queue1.pull();while (!queue2.isEmpty())queue1.offer(queue2.pull());size--;return ans;}public int top() {int temp = size;while (temp -- != 1)queue2.offer(queue1.pull());Integer ans = queue1.pull();while (!queue2.isEmpty())queue1.offer(queue2.pull());queue1.offer(ans);return ans;}public boolean empty() {return size == 0;}
}
当然本题的进阶实现是直接使用一个队列模拟栈操作,可以优化的地方就是元素转移阶段,我们可以不需要定义另一个队列暂存这些元素,而是直接让这些元素重新入队即可。整个调整过程就是,将队尾之前的所有元素出队,每个元素出队后又立刻入队到队尾,整个操作结束后,队首元素就是模拟栈的栈顶元素。代码如下。
class MyStack {private final ArrayQueue<Integer> queue;private int size = 0;public MyStack() {queue = new ArrayQueue<>(101);size = 0;}public void push(int x) {queue.offer(x);size++;}public int pop() {int temp = size - 1;while (temp -- != 0)queue.offer(queue.pull());size--;return queue.pull();}public int top() {int temp = size - 1;while (temp -- != 0)queue.offer(queue.pull());Integer ans = queue.pull();queue.offer(ans);return ans;}public boolean empty() {return size == 0;}
}
我们通过上面两个代码片段不难发现,出栈和获取栈顶元素这两个操作有重复代码,我们不妨将共有的代码提取到入栈操作处,即在入栈时就进行队列中元素的调整,让队尾元素来到队首,通过这种实现方式,在后续的出栈和获取栈顶元素时,我们直接对队首元素进行操作即可。代码如下。
class MyStack {private final ArrayQueue<Integer> queue1;private final ArrayQueue<Integer> queue2;private int size;public MyStack() {queue1 = new ArrayQueue<>(101);queue2 = new ArrayQueue<>(101);size = 0;}public void push(int x) {queue1.offer(x);int temp = size;while (temp -- != 0)queue2.offer(queue1.pull());while (!queue2.isEmpty())queue1.offer(queue2.pull());size++;}public int pop() {size--;return queue1.pull();}public int top() {return queue1.peek();}public boolean empty() {return size == 0;}
}
class MyStack {private final ArrayQueue<Integer> queue;private int size = 0;public MyStack() {queue = new ArrayQueue<>(101);size = 0;}public void push(int x) {queue.offer(x);int temp = size;while (temp -- != 0)queue.offer(queue.pull());size++;}public int pop() {size--;return queue.pull();}public int top() {return queue.peek();}public boolean empty() {return size == 0;}
}
LeetCode102. 二叉树的层序遍历
102. 二叉树的层序遍历 - 力扣(LeetCode)
二叉树的层序遍历遵循着广度优先搜索的不断延伸思想。具体来说,我们需要使用一个队列用来暂存需要遍历的结点,让根节点入队,每次取出队列中的队首结点并将其的左右孩子存入队列,不断进行此操作,就可以让队列中存储着当前层的下一层结点,实际上,队列的出队顺序就是此二叉树的层序遍历序列。

在具体实现中,由于队列只有在遍历到叶子结点后才会为空,我们需要专门定义一个变量用来存储当前层的结点数,每次取出队列元素都是基于这个变量的,否则会取出下一层的结点。
public List<List<Integer>> levelOrder(TreeNode root) {if (root == null)return new ArrayList<>();List<List<Integer>> ans = new ArrayList<>();ArrayQueue<TreeNode> queue = new ArrayQueue<>(2001);queue.offer(root);int levelNum = 1;while (!queue.isEmpty()) {List<Integer> list = new ArrayList<>();int cnt = 0;for (int i = 1; i <= levelNum; i++) {TreeNode node = queue.pull();list.add(node.val);if (node.left != null) {queue.offer(node.left);cnt++;}if (node.right != null) {queue.offer(node.right);cnt++;}}levelNum = cnt;ans.add(list);}return ans;}
LeetCode103. 二叉树的锯齿形层序遍历
103. 二叉树的锯齿形层序遍历 - 力扣(LeetCode)
本题与上题类似,我们认为根节点所处层为第一层,通过题目要求我们不难发现,当层序号为奇数时,我们需要从左到右遍历,反之,如果层序号为偶数时,我们需要从右到左遍历,这样就可以实现锯齿形遍历。我们在每层接收结果的时候需要使用一个双端队列,若当前层的层序号为奇数,我们将队列的队首结点数据从尾部插入到双端队列,否则从头部插入双端队列,后续的操作与上一题是一致的,不再赘述。
为了方便实现,我们使用了 进行实现,代码如下。
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {if (root == null)return new ArrayList<>();List<List<Integer>> ans = new ArrayList<>();LinkedList<TreeNode> queue = new LinkedList<>();queue.offer(root);int levelNum = 1;boolean isOdd = true;while (!queue.isEmpty()) {int cnt = 0;LinkedList<Integer> level = new LinkedList<>();for (int i = 1; i <= levelNum; i++) {TreeNode node = queue.poll();if (node != null) {if (isOdd)level.offerLast(node.val);elselevel.offerFirst(node.val);if (node.left != null) {queue.offer(node.left);cnt++;}if (node.right != null) {queue.offer(node.right);cnt++;}}}levelNum = cnt;isOdd = !isOdd;ans.add(level);}return ans;}
堆(优先级队列)
堆排序
堆排序是基于堆的一种排序方法,假设我们使用大顶堆进行堆内元素的排序,执行建堆操作后,堆顶元素是所有元素的最大值,我们可以选择将堆顶元素与堆的最后一个元素进行交换,然后让堆的 变量减
,这样就表示我们不再维护最大值元素,此时将交换到堆顶的元素执行一次下潜操作,新的堆顶元素就是剩下的
个元素中的最大值。不断执行此操作,直到堆中维护的元素数量为
为止。
public static void main(String[] args) {MaxHeap heap = new MaxHeap(new int[]{1, 34, 54, 13, 25, 6, 9, 17});System.out.println(Arrays.toString(heap.array));while (heap.size > 1) {heap.swap(0, heap.size - 1);heap.size --;heap.down(0);}System.out.println(Arrays.toString(heap.array));}
LeetCode215. 数组中的第 k 个最大元素
215. 数组中的第K个最大元素 - 力扣(LeetCode)
本题给定一个数组和一个整型变量 ,届时需要返回数组中第
个最大的元素。初见此题,第一想法是直接对数组进行排序,然后返回指定位置元素即可,但是这种方式并没有考虑到数组中存在重复元素的情况。
我们可以直接使用一个大顶堆来维护所有元素,然后执行 次出队操作即可。
public int findKthLargest(int[] nums, int k) {MaxHeap heap = new MaxHeap(nums);while (k -- != 0)heap.pull();return heap.peek();}
实际上,我们也并不需要维护所有的元素,直接定义一个大小为 的小顶堆,先将前
个元素存入堆中,然后继续遍历数组,若当前遍历的元素大于堆顶元素,则执行一次替换堆顶元素操作,最终堆顶元素就是第
个最大元素。
public int findKthLargest(int[] nums, int k) {MinHeap heap = new MinHeap(k);for (int i = 0; i < k; i ++)heap.offer(nums[i]);for (int i = k; i < nums.length; i ++) {if (nums[i] > heap.peek())heap.replace(nums[i]);}return heap.peek();}
总结
本文写的比较仓促,因为我要过年了。
相关文章:
2024收尾工作
目录 开场白 栈与队列 LeetCode232. 用栈实现队列 LeetCode225. 用队列实现栈 LeetCode102. 二叉树的层序遍历 LeetCode103. 二叉树的锯齿形层序遍历 堆(优先级队列) 堆排序 LeetCode215. 数组中的第 k 个最大元素 总结 开场白 今天是除夕&…...
能说说MyBatis的工作原理吗?
大家好,我是锋哥。今天分享关于【Redis为什么这么快?】面试题。希望对大家有帮助; 能说说MyBatis的工作原理吗? MyBatis 是一款流行的持久层框架,它通过简化数据库操作,帮助开发者更高效地与数据库进行交互。MyBatis…...
简单的SQL语句的快速复习
语法的执行顺序 select 4 字段列表 from 1 表名列表 where 2 条件列表 group by 3 分组前过滤 having 分组后过滤 order by 5 排序字段列表 limit 6 分页参数 聚合函数 count 统计数量 max 最大值 min 最小值 avg 平均 sum 总和 分组查询使…...
Spring MVC 综合案例
目录 一. 加法计算器 1. 准备工作 2. 约定前后端交互接口 需求分析 接口定义 3. 服务器端代码 4. 运行测试 二. 用户登录 1. 准备工作 2. 约定前后端交互接口 需求分析 接口定义 (1) 登录界面接口 (2) 首页接口 3. 服务器端代码 4. 运行测试 三. 留言板 1. 准备…...
Spring Boot多环境配置实践指南
在开发Spring Boot应用时,我们常常需要根据不同的运行环境(如开发环境、测试环境和生产环境)来配置不同的参数。Spring Boot提供了非常灵活的多环境配置机制,通过使用profile-specific properties文件,我们可以轻松地管…...
微信小程序中实现进入页面时数字跳动效果(自定义animate-numbers组件)
微信小程序中实现进入页面时数字跳动效果 1. 组件定义,新建animate-numbers组件1.1 index.js1.2 wxml1.3 wxss 2. 使用组件 1. 组件定义,新建animate-numbers组件 1.1 index.js // components/animate-numbers/index.js Component({properties: {number: {type: Number,value…...
【huawei】云计算的备份和容灾
目录 1 备份和容灾 2 灾备的作用? ① 备份的作用 ② 容灾的作用 3 灾备的衡量指标 ① 数据恢复时间点(RPO,Recoyery Point Objective) ② 应用恢复时间(RTO,Recoyery Time Objective) 4…...
Vue.js组件开发-实现下载时暂停恢复下载
在 Vue 中实现下载时暂停和恢复功能,通常可以借助 XMLHttpRequest 对象来控制下载过程。XMLHttpRequest 允许在下载过程中暂停和继续请求。 实现步骤 创建 Vue 组件:创建一个 Vue 组件,包含下载、暂停和恢复按钮。初始化 XMLHttpRequest 对…...
TCP是怎么判断丢包的?
丢包在复杂的网络环境中,是一种常见的现象。 TCP(传输控制协议)作为一种可靠传输协议,内置了多种机制来检测和处理丢包现象,从而保证数据的完整性和传输的可靠性。本文将介绍TCP判断丢包的原理和机制。 一、TCP可靠传…...
python爬虫入门(一) - requests库与re库,一个简单的爬虫程序
目录 web请求与requests库 1. web请求 1.1 客户端渲染与服务端渲染 1.2 抓包 1.3 HTTP状态代码 2. requests库 2.1 requests模块的下载 2.2 发送请求头与请求参数 2.3 GET请求与POST请求 GET请求的例子: POST请求的例子: 3. 案例:…...
2025年数学建模美赛 A题分析(3)楼梯使用方向偏好模型
2025年数学建模美赛 A题分析(1)Testing Time: The Constant Wear On Stairs 2025年数学建模美赛 A题分析(2)楼梯磨损分析模型 2025年数学建模美赛 A题分析(3)楼梯使用方向偏好模型 2025年数学建模美赛 A题分…...
复古壁纸中棕色系和米色系哪个更受欢迎?
根据最新的搜索结果,我们可以看到棕色系和米色系在复古壁纸设计中都非常受欢迎。以下是对这两种颜色系受欢迎程度的分析: 棕色系 受欢迎程度:棕色系在复古壁纸中非常受欢迎,因为它能够营造出温暖、质朴和自然的氛围。棕色系的壁纸…...
编译安装PaddleClas@openKylin(失败,安装好后报错缺scikit-learn)
编译安装 前置需求: 手工安装swig和faiss-cpu pip install swig pip install faiss-cpu 小技巧,pip编译安装的时候,可以加上--jobs64来多核编译。 注意先升级pip版本:pip install pip -U pip3 install faiss-cpu --config-s…...
t113_can增加驱动
1 基于太极派的SDK添加 //设备树添加can0: can2504000 {compatible "allwinner,sun20i-d1-can";reg <0x0 0x02504000 0x0 0x400>;interrupts <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;clocks <&ccu CLK_BUS_CAN0>;resets <&ccu RST_BUS_…...
达梦数据库建用户,键库脚本
-- 1.创建表空间 CREATE TABLESPACE "表空间名称" DATAFILE /dmdata/data/DAMENG/表空间名称.DBF SIZE 512 AUTOEXTEND ON NEXT 512 MAXSIZE UNLIMITED; -- 2.创建用户 CREATE USER "表空间名称" IDENTIFIED BY "表空间名称" HASH WITH SHA512 S…...
上海亚商投顾:沪指冲高回落 大金融板块全天强势 上海亚商投
上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 一.市场情绪 市场全天冲高回落,深成指、创业板指午后翻绿。大金融板块全天强势,天茂集团…...
MySQL 的索引类型【图文并茂】
基本分类 文本生成MindMap:https://app.pollyoyo.com/planttext <style> mindmapDiagram {node {BackgroundColor yellow}:depth(0) {BackGroundColor SkyBlue}:depth(1) {BackGroundColor lightGreen} } </style> * MySQL 索引** 数据结构角度 *** B树索引*** 哈…...
天聚地合:引领API数据流通服务,助力数字经济发展
天聚地合:引领API数据流通服务,助力数字经济发展 爱企猫01月24日消息:天聚地合(苏州)科技股份有限公司,成立于2010年,总部位于苏州,是一家综合性API数据流通服务商。公司旗下品牌‘聚合数据’已开发超过790个API,服务百万企业级客…...
【反悔堆】【hard】力扣871. 最低加油次数
汽车从起点出发驶向目的地,该目的地位于出发位置东面 target 英里处。 沿途有加油站,用数组 stations 表示。其中 stations[i] [positioni, fueli] 表示第 i 个加油站位于出发位置东面 positioni 英里处,并且有 fueli 升汽油。 假设汽车油…...
electron typescript运行并设置eslint检测
目录 一、初始化package.json 二、安装依赖 1、安装electron 2、安装typescript依赖 3、安装eslint 三、项目结构 四、配置启动项 一、初始化package.json 我的:这里的"main"没太大影响,看后面的步骤。 {"name": "xlo…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
TJCTF 2025
还以为是天津的。这个比较容易,虽然绕了点弯,可还是把CP AK了,不过我会的别人也会,还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...
