当前位置: 首页 > news >正文

每日算法一练:剑指offer——栈与队列篇(1)

1.图书整理II

        读者来到图书馆排队借还书,图书管理员使用两个书车来完成整理借还书的任务。书车中的书从下往上叠加存放,图书管理员每次只能拿取书车顶部的书。排队的读者会有两种操作:

  • push(bookID):把借阅的书籍还到图书馆。
  • pop():从图书馆中借出书籍。

为了保持图书的顺序,图书管理员每次取出供读者借阅的书籍是 最早 归还到图书馆的书籍。你需要返回 每次读者借出书的值 。

如果没有归还的书可以取出,返回 -1 。

示例 1:

输入:
["BookQueue", "push", "push", "pop"]
[[], [1], [2], []]
输出:[null,null,null,1]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.pop(); // return 1, queue is [2]

提示:

  • 1 <= bookID <= 10000
  • 最多会对 pushpop 进行 10000 次调用

用两个栈实现队列操作总结

        题目通过两个栈的配合,实现队列的两大操作:队尾插入(appendTail)队首删除(deleteHead)。以下是实现逻辑的详细总结。

核心思想

  1. 使用两个栈 AB
    • 栈 A:用于保存新插入的元素(队尾操作)。
    • 栈 B:用于保存倒序的元素(队首操作)。
  2. 倒序逻辑
    • B 为空时,将 A 中所有元素出栈并入栈到 B,使 B 中的顺序与队列的顺序一致。
  3. 操作分工:
    • appendTail(value):直接将元素压入栈 A
    • deleteHead()
      • 若栈 B 不为空,则弹出并返回 B 的栈顶元素。
      • 若栈 B 为空但栈 A 不为空,将栈 A 中所有元素转移到栈 B,然后从 B 出栈。
      • 若两个栈都为空,返回 -1

代码实现

import java.util.LinkedList;class CQueue {private LinkedList<Integer> A; // 栈 Aprivate LinkedList<Integer> B; // 栈 B// 构造函数,初始化两个栈public CQueue() {A = new LinkedList<>();B = new LinkedList<>();}// 队尾插入操作public void appendTail(int value) {A.addLast(value); // 将元素压入栈 A}// 队首删除操作public int deleteHead() {if (!B.isEmpty()) {return B.removeLast(); // 栈 B 不为空时,弹出并返回栈顶元素}if (A.isEmpty()) {return -1; // 两个栈都为空时,返回 -1}// 将栈 A 中的所有元素转移到栈 Bwhile (!A.isEmpty()) {B.addLast(A.removeLast());}return B.removeLast(); // 返回栈 B 的栈顶元素}
}

操作示例

        以输入和输出为例:

CQueue myQueue = new CQueue();
myQueue.appendTail(1); // 栈 A: [1], 栈 B: []
myQueue.appendTail(2); // 栈 A: [1, 2], 栈 B: []
System.out.println(myQueue.deleteHead()); // 输出: 1, 栈 A: [], 栈 B: [2]

复杂度分析

  1. 时间复杂度
    • appendTail:仅对栈 A 操作,时间复杂度为 O(1)。
    • deleteHead
      • B 不为空时,直接出栈操作,时间复杂度为 O(1)。
      • B 为空时,需要将栈 A 的所有元素转移到栈 B,每个元素只转移一次,因此均摊复杂度为 O(1)。
    • 总体时间复杂度:O(1)(均摊)。
  2. 空间复杂度:两个栈最多存储 N 个元素,空间复杂度为 O(N)。

2.最小栈

        请你设计一个 最小栈 。它提供 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

示例 1:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[2],[-3],[],[],[],[]]输出:
[null,null,null,null,-3,null,2,-2]解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(2);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 2.
minStack.getMin();   --> 返回 -2.

提示:

  • -231 <= val <= 231 - 1
  • poptop 和 getMin 操作总是在 非空栈 上调用
  • pushpoptop 和 getMin 最多被调用 3 * 104 次

用两个栈实现支持获取最小值的栈

题目难点

        普通栈的基本操作(push()pop()top())时间复杂度为 O(1)。但在获取最小值时,直接遍历栈会使 getMin() 的时间复杂度变为 O(N)。

目标是实现一个栈,并保证:

  • 所有操作的时间复杂度为 O(1),包括 getMin()

解题思路

利用两个栈来分别存储数据和辅助信息:

  1. 数据栈 A
    • 存储所有压入的数据元素。
    • 保证常规的栈操作(pushpoptop)正常。
  2. 辅助栈 B
    • 始终维护一个非严格降序子序列,即栈顶为当前栈的最小值。
    • 每次压入或弹出时,保持与数据栈的最小值对应关系。

辅助栈的作用:

  • 压入元素时
    • 如果栈为空或当前元素小于等于栈顶元素,将元素同步压入辅助栈。
  • 弹出元素时
    • 如果弹出的元素等于辅助栈的栈顶元素,辅助栈同步弹出。

方法设计

  1. push(x)
    • 数据栈 A 添加元素 x
    • B 为空或 x ≤ B.peek(),将 x 压入辅助栈 B
  2. pop()
    • 从数据栈 A 弹出一个元素,记为 y
    • y == B.peek(),从辅助栈 B 同步弹出。
  3. top()
    • 返回数据栈 A 的栈顶元素。
  4. getMin()
    • 返回辅助栈 B 的栈顶元素,即当前栈的最小值。

代码实现

import java.util.Stack;class MinStack {private Stack<Integer> A; // 数据栈private Stack<Integer> B; // 辅助栈(存储最小值)// 初始化栈public MinStack() {A = new Stack<>();B = new Stack<>();}// 压入栈操作public void push(int x) {A.push(x); // 压入数据栈// 如果辅助栈为空或者当前元素 <= 辅助栈顶,则同步压入if (B.isEmpty() || x <= B.peek()) {B.push(x);}}// 弹出栈操作public void pop() {// 如果弹出的元素等于辅助栈栈顶元素,则辅助栈同步弹出if (A.pop().equals(B.peek())) {B.pop();}}// 获取栈顶元素public int top() {return A.peek();}// 获取最小值public int getMin() {return B.peek(); // 辅助栈顶始终存储当前栈的最小值}
}

操作示例

public class Main {public static void main(String[] args) {MinStack minStack = new MinStack();minStack.push(3); // 数据栈: [3], 辅助栈: [3]minStack.push(4); // 数据栈: [3, 4], 辅助栈: [3]minStack.push(2); // 数据栈: [3, 4, 2], 辅助栈: [3, 2]minStack.push(2); // 数据栈: [3, 4, 2, 2], 辅助栈: [3, 2, 2]minStack.push(5); // 数据栈: [3, 4, 2, 2, 5], 辅助栈: [3, 2, 2]System.out.println(minStack.getMin()); // 输出: 2minStack.pop(); // 数据栈: [3, 4, 2, 2], 辅助栈: [3, 2, 2]System.out.println(minStack.getMin()); // 输出: 2minStack.pop(); // 数据栈: [3, 4, 2], 辅助栈: [3, 2]System.out.println(minStack.getMin()); // 输出: 2}
}

复杂度分析

  1. 时间复杂度
    • push()pop()top()getMin() 操作均为 O(1),因为每次只需操作一个或两个栈的栈顶元素。
  2. 空间复杂度
    • 最差情况下,所有元素都被压入辅助栈,空间复杂度为 O(N)。
http://www.lryc.cn/news/487766.html

相关文章:

  • 【Java】ArrayList与LinkedList详解!!!
  • 怎么用VIM查看UVM源码
  • 数据结构C语言描述3(图文结合)--双链表、循环链表、约瑟夫环问题
  • 第二十五章 TCP 客户端 服务器通信 - TCP 设备的 READ 命令
  • 【C++】哈希表的实现详解
  • 高阶C语言之五:(数据)文件
  • 服务器上部署并启动 Go 语言框架 **GoZero** 的项目
  • 【Java SE 】继承 与 多态 详解
  • 【大语言模型】ACL2024论文-16 基于地图制图的罗马尼亚自然语言推理语料库的新型课程学习方法
  • 秋招大概到此结束了
  • 华为OD机试真题---字符串化繁为简
  • 概念解读|K8s/容器云/裸金属/云原生...这些都有什么区别?
  • 初识Arkts
  • 基本的SELECT语句
  • 51c自动驾驶~合集30
  • Python Tutor网站调试利器
  • h5小游戏实现获取本机图片
  • 前端 javascript a++和++a的区别
  • OceanBase V4.x应用实践:如何排查表被锁问题
  • ctfshow-web入门-SSRF(web351-web360)
  • 【日常记录-Git】如何为post-checkout脚本传递参数
  • 《机器人控制器设计与编程》考试试卷**********大学2024~2025学年第(1)学期
  • 后台管理系统(开箱即用)
  • 5G CPE与4G CPE的主要区别有哪些
  • 量化交易系统开发-实时行情自动化交易-4.1.3.A股平均趋向指数(ADX)实现
  • tcp的网络惊群问题
  • 云原生之运维监控实践-使用Prometheus与Grafana实现对Nginx和Nacos服务的监测
  • 软考教材重点内容 信息安全工程师 第 4 章 网络安全体系与网络安全模型
  • 机器学习——期末复习 重点题归纳
  • MYSQL——数据更新