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

最小栈GO实现

[155. 最小栈]https://leetcode.cn/problems/min-stack/

    • 分析
    • 变形题
      • 思路

已解答

中等

设计一个支持 pushpoptop 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

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

示例 1:

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

提示:

  • -231 <= val <= 231 - 1
  • poptopgetMin 操作总是在 非空栈 上调用
  • push, pop, top, and getMin最多被调用 3 * 104

分析

看的艾府大大的解读,一边搬运一边记录,为了以后自己复习。

引入
给你一个数组 nums,如何计算每个前缀的最小值?

定义 preMin[i] 表示 nums[0] 到 nums[i] 的最小值。

这可以从左到右计算:

preMin[0]=nums[0]。
preMin[1]=min(nums[0],nums[1])。
preMin[2]=min(nums[0],nums[1],nums[2])=min(preMin[1],nums[2])。
preMin[3]=min(nums[0],nums[1],nums[2],nums[3])=min(preMin[2],nums[3])。
……
一般地,我们有

preMin[i]=min(preMin[i−1],nums[i])

作者:灵茶山艾府
链接:https://leetcode.cn/problems/min-stack/solutions/2974438/ben-zhi-shi-wei-hu-qian-zhui-zui-xiao-zh-x0g8/

这道题就是维护前缀和!我看有的直接用了pair这种组合,但是我这个也可以,就懒得改了。

type MinStack struct {stack    []intminStack []int
}func Constructor() MinStack {return MinStack{stack:    []int{},minStack: []int{math.MaxInt64},}
}func (this *MinStack) Push(val int) {this.stack = append(this.stack, val)tmp := min(this.minStack[len(this.minStack)-1], val)this.minStack = append(this.minStack, tmp)}func (this *MinStack) Pop() {this.stack = this.stack[:len(this.stack)-1]this.minStack = this.minStack[:len(this.minStack)-1]
}func (this *MinStack) Top() int {return this.stack[len(this.stack)-1]
}func (this *MinStack) GetMin() int {return this.minStack[len(this.minStack)-1]
}

变形题

  1. 改成队列(queue),getMin 返回队列中的最小元素。
  2. 改成双端队列(deque),getMin 返回双端队列中的最小元素。

答案在:https://codeforces.com/blog/entry/122003

思路

利用一次顺序的颠倒,为反向的出队操作准备好了完全正确的最小值数据

通过组合两个“最小栈” (MinStack) 来巧妙地实现一个**“最小队列” (MinQueue)**。

  1. 基础组件 MinStack: 首先实现一个 MinStack。它内部使用一个辅助栈,在每个元素入栈时同步记录当前栈内的最小值。这确保了 GetMin 操作的时间复杂度为 O(1)。
  2. MinQueue 的实现
    • 使用两个 MinStack:一个 inStack 作为入口(处理所有入队 Push 操作),另一个 outStack 作为出口(处理所有出队 Pop 操作)。
    • 核心机制:当需要出队但 outStack 为空时,会触发一次“倾倒”操作,将 inStack 的所有元素全部转移到 outStack。这个转移过程自动地将元素顺序颠倒,从而模拟了队列“先进先出”的特性。
    • 获取最小值:整个队列的最小值,就是 inStack 的最小值与 outStack 的最小值中的较小者,此操作复杂度也为 O(1)。

通过这种方式,代码将栈的 LIFO (后进先出) 特性转换为队列的 FIFO (先进先出) 特性,并始终保持了高效获取最小元素的能力。

我这里附上一些我这个最小栈版本的最小队列解法

package mainimport ("fmt""math"
)// ==========================================================
// 步骤一:先实现基础模块 MinStack
// 这是我们用来构建 MinQueue 的“零件”
// 它的实现与你最初的 Go 版本思路完全一致
// ==========================================================type MinStack struct {stack    []int // 存储实际数据的栈minStack []int // 辅助栈,minStack[i] 表示 stack[0...i] 的最小值
}// NewMinStack 创建一个新的最小栈实例
func NewMinStack() *MinStack {return &MinStack{stack:    []int{},// 初始化一个“哨兵”值,方便比较,避免处理空栈的边界情况minStack: []int{math.MaxInt64},}
}// Push 将元素推入栈中
func (s *MinStack) Push(val int) {s.stack = append(s.stack, val)// 获取前一个状态的最小值lastMin := s.minStack[len(s.minStack)-1]// 新的最小值是「新元素」和「前一个状态最小值」中的较小者s.minStack = append(s.minStack, min(lastMin, val))
}// Pop 从栈中弹出一个元素
func (s *MinStack) Pop() int {if s.IsEmpty() {// 在实际工程中,这里应该返回 error 或者触发 panicpanic("stack is empty")}val := s.stack[len(s.stack)-1]s.stack = s.stack[:len(s.stack)-1]s.minStack = s.minStack[:len(s.minStack)-1]return val
}// Top 获取栈顶元素
func (s *MinStack) Top() int {if s.IsEmpty() {panic("stack is empty")}return s.stack[len(s.stack)-1]
}// GetMin 在 O(1) 时间内获取栈中最小元素
func (s *MinStack) GetMin() int {return s.minStack[len(s.minStack)-1]
}// IsEmpty 检查栈是否为空
func (s *MinStack) IsEmpty() bool {return len(s.stack) == 0
}// ==========================================================
// 步骤二:使用两个 MinStack 实现 MinQueue
// ==========================================================type MinQueue struct {inStack  *MinStack // 负责处理入队 (Push)outStack *MinStack // 负责处理出队 (Pop)
}// Constructor 创建一个新的最小队列实例
func Constructor() *MinQueue {return &MinQueue{inStack:  NewMinStack(),outStack: NewMinStack(),}
}// Push 将元素推入队列尾部
func (q *MinQueue) Push(val int) {// 所有新元素都直接进入 inStackq.inStack.Push(val)
}// transfer 是核心辅助函数,负责在需要时将元素从 inStack "倾倒" 到 outStack
func (q *MinQueue) transfer() {// 只有当 outStack 为空时,才需要倾倒// 如果 outStack 不为空,说明队头元素还在,不能打乱顺序if q.outStack.IsEmpty() {// 将 inStack 的所有元素逐个弹出,并压入 outStack// 这个过程会自动反转元素的顺序,并正确地构建 outStack 的最小值历史for !q.inStack.IsEmpty() {q.outStack.Push(q.inStack.Pop())}}
}// Pop 从队列头部移除元素
func (q *MinQueue) Pop() int {// 在执行出队操作前,先调用 transfer 确保 outStack 中有元素(如果可能的话)q.transfer()if q.outStack.IsEmpty() {panic("queue is empty")}return q.outStack.Pop()
}// Peek 获取队列头部的元素,但不移除
func (q *MinQueue) Peek() int {q.transfer()if q.outStack.IsEmpty() {panic("queue is empty")}return q.outStack.Top()
}// GetMin 在 O(1) 时间内获取队列中最小元素
func (q *MinQueue) GetMin() int {// 队列的全部元素分散在两个栈中// 整个队列的最小值就是这两个栈各自最小值的较小者minIn := q.inStack.GetMin()minOut := q.outStack.GetMin()return min(minIn, minOut)
}// IsEmpty 检查队列是否为空
func (q *MinQueue) IsEmpty() bool {return q.inStack.IsEmpty() && q.outStack.IsEmpty()
}// min 是一个辅助函数,返回两个整数中的较小者
func min(a, b int) int {if a < b {return a}return b
}// ==========================================================
// 主函数:用法示例
// ==========================================================func main() {mq := Constructor()fmt.Println("Push 5, GetMin:", func() int { mq.Push(5); return mq.GetMin() }())   // 输出 5fmt.Println("Push 2, GetMin:", func() int { mq.Push(2); return mq.GetMin() }())   // 输出 2fmt.Println("Push 8, GetMin:", func() int { mq.Push(8); return mq.GetMin() }())   // 输出 2fmt.Println("--------------------")fmt.Println("Pop:", mq.Pop(), " GetMin:", mq.GetMin())    // Pop 5, 剩下 [2, 8], 最小值为 2fmt.Println("Push 1, GetMin:", func() int { mq.Push(1); return mq.GetMin() }())   // Push 1, 剩下 [2, 8, 1], 最小值为 1fmt.Println("Pop:", mq.Pop(), " GetMin:", mq.GetMin())    // Pop 2, 剩下 [8, 1], 最小值为 1fmt.Println("Pop:", mq.Pop(), " GetMin:", mq.GetMin())    // Pop 8, 剩下 [1], 最小值为 1
}
http://www.dtcms.com/a/457306.html

相关文章:

  • 福田欧辉是国企吗做百度手机网站优化点
  • npm 扩展vite
  • 和15岁女儿做很舒服网站最新网页版传奇
  • 01.MMDetection3D训练
  • 手机 网站制作什么网站资源多
  • C++之日期类的实现
  • 构建AI智能体:五十七、LangGraph + Gradio:构建可视化AI工作流的趣味指南
  • Create/Assemble/Link x64 Windows
  • 网站建设与管理案例教程第三版答案中国货源大全网
  • 织梦建网站建设收费网站
  • Delphi字段值含有空格
  • 【第五章:计算机视觉-项目实战之生成式算法实战:扩散模型】2.CV黑科技:生成式算法理论-(3)经典扩散模型DDPM算法流程讲解
  • 牛客算法_哈希
  • Product Hunt 每日热榜 | 2025-10-08
  • 重庆建站公司官网国外有名的网站
  • 【论文阅读】Visual Planning: Let’s Think Only with Images
  • 河南教育平台网站建设为中小型企业构建网站
  • 开放指令编辑创新突破!小米开源 Lego-Edit 登顶 SOTA:用强化学习为 MLLM 编辑开辟全新赛道!
  • Vue 与 React 深度对比:底层原理、开发体验与实际性能
  • 平台网站建设协议电话网站域名到期
  • Spring Gateway 全面解析:从入门到进阶实践​
  • 江西九江网站建设注册登记
  • 建个微网站多少钱tv网站建设
  • Docker 说明与安装
  • Docker 镜像结构与相关核心知识总结
  • 容器技术与 Docker 入门部署
  • linux学习笔记(20)线程
  • Vue3后台表单快速开发
  • 前端技术栈 —— 创建React项目
  • 推荐一个 GitHub 开源项目信息卡片生成工具,支持Docker快速部署和API调用