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

(huawei)最小栈

最小栈:O(1)时间获取栈最小值的双栈解法详解

引言:为什么需要“最小栈”?

在常规栈(Stack)数据结构中,我们可以轻松实现push(入栈)、pop(出栈)、top(获取栈顶元素)三个核心操作,且时间复杂度均为O(1)。但在实际开发中,我们经常会遇到一个需求——快速获取当前栈中的最小值,比如在表达式计算、单调栈相关算法中。

如果直接使用常规栈实现“获取最小值”功能,最直接的思路是遍历整个栈查找最小值,此时时间复杂度会退化为O(n)(n为栈中元素个数),在数据量较大时效率极低。因此,我们需要设计一种特殊的栈结构(即“最小栈”),让getMin(获取最小值)操作也能达到O(1) 时间复杂度。

核心思路:双栈协同实现最小栈

要让getMin操作达到O(1),关键在于“提前记录最小值”——用一个辅助栈同步存储主栈中的“当前最小值”,通过双栈协同确保辅助栈的栈顶始终是主栈的最小值。

双栈分工

  • 主栈(min_stack1):存储所有入栈元素,承担常规栈的pushpoptop功能。
  • 辅助栈(min_stack2):仅存储主栈中的“阶段性最小值”,栈顶元素始终是当前主栈的最小值。

核心规则(重点!)

辅助栈的操作需要严格遵循以下规则,才能保证栈顶始终是最小值:

  1. 入栈(push)

    • 先将元素压入主栈;
    • 若辅助栈为空,或当前元素小于等于辅助栈顶元素,则将该元素也压入辅助栈(“小于等于”是为了处理重复最小值的情况,避免漏记)。
  2. 出栈(pop)

    • 先判断主栈顶元素是否与辅助栈顶元素相等(若相等,说明当前最小值即将被弹出,辅助栈需同步弹出);
    • 再将主栈顶元素弹出。
  3. 获取最小值(getMin):直接返回辅助栈顶元素(此时栈顶已保证是主栈当前最小值)。

  4. 获取栈顶(top):直接返回主栈顶元素(与常规栈一致)。

代码实现与逐行解析(C++版)

下面基于题目中的代码,逐函数拆解实现逻辑,并补充关键注释。

完整代码

#include <stack>
using namespace std;class MinStack {// 主栈:存储所有元素stack<int> min_stack1;// 辅助栈:存储当前最小值,栈顶始终是主栈的最小值stack<int> min_stack2;
public:/** 构造函数:初始化栈(默认构造即可,无需额外操作) */MinStack() {// stack容器的默认构造函数已完成初始化,无需手动清空}/** 入栈操作:主栈必压,辅助栈按需压 */void push(int x) {// 1. 元素先压入主栈min_stack1.push(x);// 2. 辅助栈为空 或 当前元素<=辅助栈顶(保证最小值不丢失),则压入辅助栈if (min_stack2.empty() || min_stack2.top() >= x) {min_stack2.push(x);}}/** 出栈操作:主栈必弹,辅助栈按需弹 */void pop() {// 1. 若主栈顶等于辅助栈顶(当前最小值要被弹出),辅助栈同步弹出if (min_stack1.top() == min_stack2.top()) {min_stack2.pop();}// 2. 主栈弹出顶部元素min_stack1.pop();}/** 获取主栈顶元素 */int top() {return min_stack1.top();}/** 获取当前栈的最小值(直接返回辅助栈顶) */int getMin() {return min_stack2.top();}
};/** 实例化与调用示例 */
// int main() {
//     MinStack* obj = new MinStack();
//     obj->push(-2);  // 主栈:[-2],辅助栈:[-2]
//     obj->push(0);   // 主栈:[-2,0],辅助栈:[-2](0 > -2,不压辅助栈)
//     obj->push(-3);  // 主栈:[-2,0,-3],辅助栈:[-2,-3](-3 <= -2,压辅助栈)
//     cout << "当前最小值:" << obj->getMin() << endl;  // 输出 -3
//     obj->pop();     // 主栈弹出-3,辅助栈同步弹出-3 → 主栈:[-2,0],辅助栈:[-2]
//     cout << "栈顶元素:" << obj->top() << endl;       // 输出 0
//     cout << "当前最小值:" << obj->getMin() << endl;  // 输出 -2
//     delete obj;     // 释放内存
//     return 0;
// }

关键细节答疑

  1. 为什么辅助栈要存“小于等于”的元素,而不是“小于”?
    假设主栈依次入栈 2 → 2

    • 若辅助栈只存“小于”的元素:第一次入栈2(辅助栈[2]),第二次入栈2(2不小于辅助栈顶,不存);
    • 当主栈弹出第一个2时,主栈剩余[2],但辅助栈已空,此时getMin会报错。
      因此,“小于等于”能确保重复最小值被同步记录,避免最小值丢失。
  2. 出栈时为什么要先判断辅助栈,再弹主栈?
    若先弹主栈,主栈顶元素已被删除,无法再与辅助栈顶对比,会导致辅助栈的最小值无法同步更新。

复杂度分析

操作时间复杂度空间复杂度
push(x)O(1)O(n)
pop()O(1)O(n)
top()O(1)O(n)
getMin()O(1)O(n)
  • 时间复杂度:所有操作均为栈的基础操作(push/pop/top),均为常数时间O(1)。
  • 空间复杂度:最坏情况下(主栈元素严格递减,如5→4→3→2→1),辅助栈需存储所有元素,空间复杂度为O(n)(n为主栈元素个数)。

拓展思考:单栈解法 vs 双栈解法

除了双栈法,还有一种常见的“单栈解法”——用栈存储“元素值+当前最小值”的键值对(pair<int, int>),每次入栈时计算新的最小值(当前元素与栈顶最小值的较小者)。

单栈解法示例代码

class MinStack {stack<pair<int, int>> st;  // pair<当前元素, 当前栈最小值>
public:MinStack() {}void push(int x) {if (st.empty()) {st.push({x, x});  // 空栈时,元素本身就是最小值} else {// 新最小值 = min(当前元素, 栈顶最小值)int new_min = min(x, st.top().second);st.push({x, new_min});}}void pop() {st.pop();  // 弹出键值对,最小值同步更新}int top() {return st.top().first;  // 返回当前元素}int getMin() {return st.top().second;  // 返回当前最小值}
};

两种解法对比

维度双栈解法单栈解法
逻辑直观性稍复杂(需理解双栈协同)更直观(键值对绑定关系)
空间开销最坏O(n),最好O(1)(主栈递增时)固定O(n)(每个元素都带最小值)
代码简洁度略繁琐(两个栈操作)更简洁(单个栈操作)

实际开发中可根据需求选择:若追求空间最优(主栈递增场景多),选双栈法;若追求代码简洁和直观,选单栈法。

总结

最小栈的核心是“用辅助空间换时间”——通过额外的辅助栈(或键值对)提前记录最小值,将getMin操作从O(n)优化到O(1),同时保证pushpop操作仍为O(1)。

双栈解法的关键在于辅助栈的“按需入栈/出栈”规则(小于等于入栈、相等出栈),只要掌握这一规则,就能轻松实现高效的最小栈。建议结合文中的main函数测试用例,手动模拟栈的变化过程,加深对逻辑的理解!

http://www.dtcms.com/a/545927.html

相关文章:

  • 四川建设网官网住房和城乡厅网站文字很少怎么做优化
  • apache 配置网站茶叶网站源码php
  • 南昌自主建站模板建设标准网站
  • PyTorch 基础详解:tensor.item() 方法
  • 外贸网站 php基于云平台网站群建设
  • 产品设计网站官网制作人是做什么的
  • 【每天一个知识点】“社区检测”(Community Detection)
  • 建站之星 discuz广州开发区东区
  • 04-函数与模块-练习
  • 网站seo教材中国建设银行校园招聘网站
  • 原型样网站做网站代理
  • 临海响应式网站设计wordpress移动应用
  • Rust生命周期与泛型的组合使用深度解析
  • 张家港网站建设服务全网营销公司排名前十
  • 网站建设廴金手指花总壹陆陈村九江网站建设
  • 合并两个排序的链表
  • 网站维护和建设工作范围昆明网站建设电话
  • 手机网站开发学习视频给wordpress权限
  • 广州五屏网站建设wordpress 上传到域名
  • 如何在uni-app中禁用iOS橡皮筋效果?
  • 安徽合肥做网站的公司免费企业网站程序
  • LangChain4j学习9:结构化输出
  • 公司介绍网站源码百度aipage智能建站系统
  • PyTorch快速搭建CV模型实战
  • 索引的数据结构
  • 仓颉语言中的协程调度机制深度解析
  • 对网站设计的建议长沙工商注册网上核名
  • 大连企业制作网站上海专业的网络推广
  • 代做设计网站wordpress添加后台菜单
  • Adobe Illustrator 和 Adobe Photoshop 比较异同