小哆啦解题记:守护最小值的魔法栈

155. 最小栈 - 力扣(LeetCode)

🎬 第一幕:小哆啦的栈塔挑战

力扣大陆的天空,悬浮着一座高耸的"栈塔"。塔门口,一行火红的文字闪烁:

"想进塔顶,先回答这个问题:

设计一个能 随时告诉我最小值 的栈,所有操作必须 O(1) ,包括 pushpoptopgetMin。"

小哆啦眼睛一亮:

"这不就是普通栈 + Math.min 吗?小菜一碟!"

于是他写下了第一版代码:

typescript 复制代码
class MinStack {
    private stack: number[] = [];
    push(val: number) { this.stack.push(val); }
    pop() { this.stack.pop(); }
    top() { return this.stack[this.stack.length - 1]; }
    getMin() { return Math.min(...this.stack); } // 看,多优雅!
}

他兴冲冲按下运行按钮,力扣精灵冷冷吐出一句话:

"getMin() 时间复杂度 O(n),你确定敢带这代码进塔?"

小哆啦吓了一跳:

"哎呀,我每次 Math.min 都要遍历一遍栈,确实慢到怀疑人生。"

他第一次意识到:

  • 栈操作可以 O(1),但 getMin 每次 O(n),整体性能差到爆炸。
  • 如果有百万次 getMin,程序直接凉凉。

🧠 第二幕:为什么 O(1) 难住了小哆啦?

小哆啦在树下沉思:

"pushpop 好办,但 getMin 怎么做到 O(1) 呢?

如果能提前记住最小值就好了,可问题是------最小值可能会被 pop 掉!"

哆啦A梦递过一本秘籍,封面写着:
《辅助栈:记录历史最低点》

秘籍核心思想:

每次 push,一个栈存当前值,另一个栈同步记录当前最小值的"快照"。
pop 时两个栈一起退,保证最小值信息不会乱。

举个例子:
push 5 → minStack = [5]
push 3 → minStack = [5, 3]
push 7 → minStack = [5, 3, 3]

为什么第三次还是 3?因为 7 比 3 大,最小值还是 3,所以复制一遍最小值


⚔️ 第三幕:魔法代码诞生

kotlin 复制代码
class MinStack {
    private stack: number[] = [];
    private minStack: number[] = [];

    push(val: number): void {
        this.stack.push(val);
        const minVal = this.minStack.length === 0 ? val : Math.min(val, this.minStack[this.minStack.length - 1]);
        this.minStack.push(minVal);
    }

    pop(): void {
        this.stack.pop();
        this.minStack.pop();
    }

    top(): number {
        return this.stack[this.stack.length - 1];
    }

    getMin(): number {
        return this.minStack[this.minStack.length - 1];
    }
}

每次 push,记录历史最小值快照

getMin → 直接取辅助栈末尾,O(1)

pop → 两个栈同步退位,状态永远一致


🏆 第四幕:空间换时间的哲学

小哆啦写下心得:

  • 以前:每次 getMin 扫一遍 → 时间爆炸
  • 现在:每次 push 多存一个数 → 空间略大,但性能飞升
  • 典型的"空间换时间",就像哆啦A梦的口袋,随手一个道具换取无限可能。

🧩 第五幕:进阶优化------如何压缩空间?

突然,胖虎冷笑:

"你这辅助栈太胖了!能不能减肥?"

小哆啦灵机一动:

"其实没必要在 minStack 复制所有最小值,只在遇到 更小值 时才 push,pop 时如果 top 是当前最小值,再 pop 一次。"

优化版代码:

kotlin 复制代码
class MinStack {
    private stack: number[] = [];
    private minStack: number[] = [];

    push(val: number): void {
        this.stack.push(val);
        if (this.minStack.length === 0 || val <= this.minStack[this.minStack.length - 1]) {
            this.minStack.push(val);
        }
    }

    pop(): void {
        const val = this.stack.pop();
        if (val === this.minStack[this.minStack.length - 1]) {
            this.minStack.pop();
        }
    }

    top(): number {
        return this.stack[this.stack.length - 1];
    }

    getMin(): number {
        return this.minStack[this.minStack.length - 1];
    }
}

✅ 空间优化成功:minStack 只存最小值的历史节点

✅ 仍然保持 O(1) 查询

✅ 压缩内存,胖虎终于满意


🎯 栈 VS 辅助栈对比总结

方法 getMin复杂度 空间 可维护性
暴力遍历 O(n) O(1) 简单但低效
辅助栈 O(1) O(n) 稳定快速
空间压缩版 O(1) O(k) (k ≪ n) 进阶最优

🏁 终章:哲学彩蛋

小哆啦仰望栈塔:

"原来,辅助栈就像人生的备份系统,帮你记住最低谷的每一步。

只有记住自己的'最小值',你才能在关键时刻快速反应。"

相关推荐
一只齐刘海的猫2 小时前
【Leetcode】找到字符串中所有字母异位词
算法·leetcode·职场和发展
海清河晏1112 小时前
数据结构 | 八大排序
数据结构·算法·排序算法
IronMurphy3 小时前
【算法五十七】146. LRU 缓存
算法·缓存
凌波粒4 小时前
LeetCode--108.将有序数组转换为二叉搜索树(二叉树)
算法·leetcode·职场和发展
liulilittle4 小时前
KCC:在 BBR 思路上的一次探索
网络·tcp/ip·算法·bbr·通信·拥塞控制·kcc
浦信仿真大讲堂4 小时前
达索系统SIMULIA Abaqus 2026接触和约束的增强新功能介绍
人工智能·python·算法·仿真软件·达索软件
点云侠5 小时前
PCL 生成三棱锥点云
c++·算法·最小二乘法
兰令水5 小时前
leecodecode【面试150】【2026.6.13打卡-java版本】
java·算法·leetcode
临沂堇5 小时前
刷题日志 | Leetcode Hot 100 哈希
算法·leetcode·哈希算法
玉小格5 小时前
一次关于Python的总结
算法