单靠list.append()无法满足o(1)取最小值,因为list不维护最小值信息,min()为o(n),且仅缓存self._min无法在pop时o(1)还原上一最小值。

为什么单靠list.append()无法满足O(1)取最小值
Python 的 list 本身没有维护最小值信息,每次调用 min() 都是 O(n);即使缓存一个 self._min 变量,弹出时也无法在 O(1) 内还原上一个最小值——因为栈是后进先出,历史最小值可能已被覆盖或丢弃。
用辅助栈同步记录最小值的正确姿势
核心思路:用另一个栈 self._min_stack 跟踪每个状态下的最小值。入栈时,如果新元素 ≤ 当前最小值(即 _min_stack[-1]),就把它也压入辅助栈;出栈时,若主栈弹出的是当前最小值,辅助栈也同步弹出。
关键细节:
-
_min_stack初始应推入一个极大值(如float('inf'))或留空,但判空逻辑必须统一 - 比较必须用
而非 <code>,否则重复最小值(如 <code>[3,1,1,4])会导致辅助栈少存一个1,get_min()在第二次pop()后失效 - 所有操作(
push、pop、get_min)都严格 O(1),空间最坏 O(n),但这是必要代价
示例片段:
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
class MinStack:
def __init__(self):
self._stack = []
self._min_stack = [float('inf')] # 哨兵,避免判空
<pre class="brush:python;toolbar:false;">def push(self, x: int) -> None:
self._stack.append(x)
if x <= self._min_stack[-1]:
self._min_stack.append(x)
def pop(self) -> None:
if self._stack.pop() == self._min_stack[-1]:
self._min_stack.pop()
def get_min(self) -> int:
return self._min_stack[-1]
不用辅助栈的替代方案:栈内存储差值
节省空间但更易出错。原理是栈中不存原始值,而存「当前值与历史最小值的差」,并单独维护一个 self._min 变量。入栈时计算差值,若差值为负,说明更新了最小值,同时更新 _min;出栈时若差值为负,需先还原旧的 _min 再弹出。
问题点:
- 涉及整数溢出风险(Python 一般不爆,但逻辑上差值可能超
int范围) -
get_min()看似 O(1),但pop()里的分支判断和变量更新稍复杂,调试困难 - 可读性差,协作或半年后回看容易误判逻辑
测试时最容易漏掉的边界场景
光测 [1,2,3] 或 [3,2,1] 不够。必须覆盖:
- 空栈调用
get_min()—— 应抛IndexError或提前检查 - 连续压入相同最小值:
push(2), push(2), push(1), push(1),再反复pop(),验证get_min()始终准确 - 仅一个元素后立即
pop()再get_min()—— 辅助栈只剩哨兵,返回值是否合理
真正麻烦的不是实现,而是把「最小值的历史快照」和「栈的生命周期」对齐。只要辅助栈的进出和主栈严格耦合,其余都是细节。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










