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

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) 进阶最优

🏁 终章:哲学彩蛋

小哆啦仰望栈塔:

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

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

相关推荐
ZLRRLZ26 分钟前
【数据结构】二叉树进阶算法题
数据结构·c++·算法
arin8762 小时前
【图论】倍增与lca
算法·图论
CoovallyAIHub2 小时前
别卷单模态了!YOLO+多模态 才是未来场景实战的“天选方案”
深度学习·算法·计算机视觉
guozhetao2 小时前
【图论,拓扑排序】P1347 排序
数据结构·c++·python·算法·leetcode·图论·1024程序员节
慕雪_mx2 小时前
最短路算法
算法
AI_Keymaker2 小时前
对话DeepMind创始人Hassabis:AGI、宇宙模拟与人类文明的下一个十年
算法
yi.Ist2 小时前
关于二进制的规律
算法·二进制·bitset
88号技师3 小时前
2025年7月一区SCI-投影迭代优化算法Projection Iterative Methods-附Matlab免费代码
开发语言·人工智能·算法·机器学习·matlab·优化算法
草香农3 小时前
SHA-3算法详解
算法
花海如潮淹3 小时前
量子算法可视化工具:撕裂量子黑箱的破壁者
经验分享·笔记·算法·量子计算