栈题解——最小栈【LeetCode】

155. 最小栈

题目描述

设计一个支持 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],[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
  • poptop 和 getMin 操作总是在 非空栈 上调用
  • pushpoptop, and getMin最多被调用 3 * 104 次

我们来分析这段实现 支持常数时间获取最小值的栈(MinStack) 的代码,从三个角度出发:


一、算法逻辑讲解(思路分步)

整体目标:
设计一个栈结构,要求支持四种操作:

  • push(val): 入栈元素 val;
  • pop(): 弹出栈顶元素;
  • top(): 获取栈顶元素;
  • getMin(): 获取当前栈中的最小值。
初始化
self.st = [(0, inf)]
  • 初始化时栈中放入一个哨兵 (0, inf)
    • 0 是占位数,实际不用,避免栈为空的边界判断。
    • inf 是正无穷,表示最小值的初始值永远不会被使用。
    • 用一个 二元组 表示栈元素:(val, 当前最小值),这样可以实现 O(1) 取最小值。
push(val)
self.st.append((val, min(self.st[-1][1], val)))
  • 每次压入新值 val同时记录当前栈中的最小值
    • self.st[-1][1] 是栈顶记录的“之前”的最小值;
    • min(...) 是“当前”与“之前”最小值取更小的那个;
    • 所以每个栈元素都带着“当前入栈时的最小值”。
pop()
self.st.pop()
  • 弹出栈顶元素,直接 pop 即可;
  • 由于最小值是绑定在元素上的,所以不会丢失信息。
top()
return self.st[-1][0]
  • 返回栈顶的元素值。
getMin()
return self.st[-1][1]
  • 返回栈顶记录的当前最小值。

二、算法核心点(关键技巧)

✅ 核心技巧:栈中每个元素都附带一个当前最小值

这是本算法的关键优化 ——

  • 在入栈的时候,提前计算好每个状态下的最小值并存储下来;
  • 这样在 getMin() 的时候就能做到 O(1) 时间复杂度;
  • 所以不是每次动态去遍历栈找最小值,而是把“最小值随时间演变的轨迹”记录在每个节点中。

这种结构也被称为 “辅助栈思想” 的一种优化实现(实际上这里是“主栈 + 最小值绑定”)。

class MinStack:
    def __init__(self):
        # 这里的 0 写成任意数都可以,反正用不到
        self.st = [(0, inf)]  # 栈底哨兵

    def push(self, val: int) -> None:
        self.st.append((val, min(self.st[-1][1], val)))

    def pop(self) -> None:
        self.st.pop()

    def top(self) -> int:
        return self.st[-1][0]

    def getMin(self) -> int:
        return self.st[-1][1]

三、复杂度分析

时间复杂度(所有操作):
  • push: O(1)
  • pop: O(1)
  • top: O(1)
  • getMin: O(1)

因为每个操作都只涉及栈顶元素的访问或更新,无需遍历。

空间复杂度:
  • O(n),其中 n 是入栈的元素个数。
  • 每个元素都存储了一个 (val, 当前最小值) 的二元组,因此是线性空间。

总结

维度

说明

✅ 思路逻辑

每个入栈元素都记录当前最小值

✅ 核心技巧

元素与当前最小值打包记录,空间换时间

✅ 时间复杂度

所有操作均为 O(1)

✅ 空间复杂度

O(n),每个入栈值都额外记录一个最小值

如需我用图示说明这段栈在操作过程中的状态变化,也可以继续补充!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值