[LeetCode 155]最小栈

本文介绍了一个支持push、pop、top及getMin操作的最小栈的设计与实现。getMin操作可在常数时间内检索到栈中的最小元素。通过两个栈的辅助结构,确保了高效地进行最小值查询。

[LeetCode 155]C++实现最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

来源:力扣(LeetCode 155)
链接:https://leetcode-cn.com/problems/min-stack

class MinStack {
public:
    stack<int>min_stack;
    stack<int>data_stack;

    /** initialize your data structure here. */
    MinStack() {
    }
    
    void push(int x) {
        data_stack.push(x);
        if(min_stack.empty()){
            min_stack.push(x);
        }
        else{
            if(x>min_stack.top()){
                x=min_stack.top();
            }
            min_stack.push(x);
        }
    }
    void pop() {
        data_stack.pop();
        min_stack.pop();
    }
    
    int top() {
        return data_stack.top();
    }
    
    int getMin() {
        return min_stack.top();
    }
};
【最优潮流】直流最优潮流(OPF)课设(Matlab代码实现)内容概要:本文档主要围绕“直流最优潮流(OPF)课设”的Matlab代码实现展开,属于电力系统优化领域的教学与科研实践内容。文档介绍了通过Matlab进行电力系统最优潮流计算的基本原理与编程实现方法,重点聚焦于直流最优潮流模型的构建与求解过程,适用于课程设计或科研入门实践。文中提及使用YALMIP等优化工具包进行建模,并提供了相关资源下载链接,便于读者复现与学习。此外,文档还列举了大量与电力系统、智能优化算法、机器学习、路径规划等相关的Matlab仿真案例,体现出其服务于科研仿真辅导的综合性平台性质。; 适合人群:电气工程、自动化、电力系统及相关专业的本科生、研究生,以及从事电力系统优化、智能算法应用研究的科研人员。; 使用场景及目标:①掌握直流最优潮流的基本原理与Matlab实现方法;②完成课程设计或科研项目中的电力系统优化任务;③借助提供的丰富案例资源,拓展在智能优化、状态估计、微电网调度等方向的研究思路与技术手段。; 阅读建议:建议读者结合文档中提供的网盘资源,下载完整代码与工具包,边学习理论边动手实践。重点关注YALMIP工具的使用方法,并通过复现文中提到的多个案例,加深对电力系统优化问题建模与求解的理解。
本程序为针对江苏省中医院挂号系统设计的自动化预约工具,采用Python语言编写。项目压缩包内包含核心配置文件与主执行文件。 配置文件conf.ini中,用户需根据自身情况调整身份验证参数:可填写用户名与密码,或直接使用有效的身份令牌(若提供令牌则无需填写前两项)。其余配置项通常无需更改。 主文件main.py包含两项核心功能: 1. 预约测试模块:用于验证程序运行状态及预约流程的完整性。执行后将逐步引导用户选择院区、科室类别、具体科室、医师、就诊日期、时段及具体时间,最后确认就诊卡信息。成功预约后将返回包含预约编号及提示信息的结构化结果。 2. 监控预约模块:可持续监测指定医师在设定日期范围内的可预约时段。一旦检测到空闲号源,将自动完成预约操作。该模块默认以10秒为间隔循环检测,成功预约后仍会持续运行直至手动终止。用户需注意在预约成功后及时完成费用支付以确认挂号。 程序运行时会显示相关技术支持信息,包括采用的验证码识别组件及训练数据来源。操作界面采用分步交互方式,通过输入序号完成各环节选择。所有网络请求均经过结构化处理,返回结果包含明确的状态码与执行耗时。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
<think>我们讨论的是LeetCode 155题“最小”。题目要求设计一个,除了常规的push、pop、top操作外,还能在常数时间内检索到中的最小元素。根据引用[1][2][3][4][5],我们看到了几种不同的实现方法,现在需要分析并给出最优解法。 ### 方法对比 1. **双法(两个)**:引用[1][3]使用两个,一个存储数据,另一个存储当前最小值。每次push时,如果新元素小于等于最小顶,则压入最小;pop时,如果弹出的元素等于最小顶,则最小也弹出。但注意,引用[1]和[3]的实现中,最小每次push都会压入当前最小值(即使新元素比当前最小值大,也重复压入当前最小值)。这样,两个的大小始终保持一致,pop时同时弹出即可。 2. **单法(使用数组/元组)**:引用[2]使用一个,但中每个元素是一个数组(或元组),其中第一个元素是当前值,第二个元素是从底到该元素时的最小值。这样,每次push时,当前元素的最小值可以通过比较新元素和顶元素的最小值得到。这种方法只需要一个,但每个元素存储的信息更多。 3. **优化双法(最小非同步压入)**:引用[4]提到,最小只有在遇到小于等于当前最小值的元素时才压入。这样,最小中的元素不会重复,且数量会少于主。pop时,只有弹出的元素等于最小顶时,最小才弹出。 ### 最优解法分析 - **时间效率**:三种方法在push、pop、top、getMin操作的时间复杂度都是$O(1)$,满足题目要求。 - **空间效率**:方法1(双同步)在最坏情况下(所有元素递减)空间为$2n$。方法2(单)每个元素存储两个值,空间也是$2n$。方法3(最小非同步)在最好情况下(元素递增)最小只存储一个元素,空间为$n+1$;最坏情况(递减)空间为$2n$。因此,方法3在空间上更优。 - **实现复杂度**:方法1和方法2实现简单,且pop操作不需要判断,直接弹出。方法3在pop时需要判断主弹出的元素是否等于最小顶,如果相等则弹出最小,实现稍复杂,但节省空间。 ### 最优解法:优化双法(最小非同步压入) 参考引用[4],我们采用以下策略: - 使用两个:主`stack`和最小`min_stack`。 - `push(x)`操作: - 主直接压入`x`。 - 如果最小为空,或者`x`小于等于最小顶元素,则将`x`压入最小。 - `pop()`操作: - 弹出主顶元素,记为`val`。 - 如果`val`等于最小顶元素,则弹出最小顶。 - `top()`:返回主顶。 - `getMin()`:返回最小顶。 **注意**:为什么使用小于等于?考虑连续压入相同最小值的情况,例如:push(0), push(1), push(0)。第一个0压入最小,然后压入1(不压入最小),再压入0,此时0等于最小顶0,所以压入。这样,当pop第一个0时,最小的0被弹出,而第二个0还在,保证了正确性。 ### 代码实现(C++) ```cpp class MinStack { private: stack<int> data_stack; stack<int> min_stack; public: MinStack() {} void push(int val) { data_stack.push(val); // 当最小为空,或者新元素小于等于最小顶时,压入最小 if (min_stack.empty() || val <= min_stack.top()) { min_stack.push(val); } } void pop() { if (data_stack.empty()) return; int val = data_stack.top(); data_stack.pop(); // 如果弹出的元素等于最小顶,则弹出最小 if (val == min_stack.top()) { min_stack.pop(); } } int top() { return data_stack.top(); } int getMin() { return min_stack.top(); } }; ``` ### 示例演算(以引用[5]的操作为例) 操作序列:`push(-2)`, `push(0)`, `push(-3)`, `getMin()`, `pop()`, `top()`, `getMin()` | 操作 | 主底→顶) | 最小底→顶) | 返回值 | 说明 | |----------------|-------------------|---------------------|--------|--------------------------------------| | 初始化 | [] | [] | | | | push(-2) | [-2] | [-2] | | 最小空,压入-2 | | push(0) | [-2,0] | [-2] | | 0>-2,最小不变 | | push(-3) | [-2,0,-3] | [-2,-3] | | -3<-2,压入-3 | | getMin() | | | -3 | 最小顶为-3 | | pop() | [-2,0] | [-2] | | 弹出主-3,等于最小顶-3,弹出 | | top() | | | 0 | 主顶为0 | | getMin() | | | -2 | 最小顶为-2 | ### 空间复杂度分析 - 最坏情况:元素递减,每个新元素都小于前一个,最小和主大小相同,空间复杂度$O(n)$。 - 最好情况:元素递增,最小只存储第一个元素,空间复杂度$O(1)$(最小大小1,主大小n)。 - 平均情况:空间复杂度$O(n)$,但实际使用空间小于等于同步双法。 ### 相关问题 1. 为什么最小的push条件要包含等于的情况? 2. 如果中存储的是对象(而非基本类型),如何修改比较逻辑? 3. 在并发环境下,如何保证最小的线程安全? [^1]: 双同步压入法,空间复杂度为$O(2n)$ [^2]: 单存储元组法,空间复杂度$O(2n)$ [^3]: 双非同步压入法,空间复杂度最坏$O(2n)$,最好$O(1)$ [^4]: 最小只在必要时压入,节省空间 [^5]: 操作序列示例</think>### LeetCode 155 最小最优解法详解 最小要求在常数时间内实现 `push`、`pop`、`top` 和 `getMin` 操作。最优解法采用**双结构 + 非同步压策略**,在保证 $O(1)$ 时间复杂度的同时优化空间效率。 #### 核心思想 1. **双结构**: - `data_stack`:存储常规数据 - `min_stack`:存储当前最小值 2. **非同步压**: - 仅当新元素 $\leq$ `min_stack` 顶时,才压入 `min_stack` - 避免存储冗余的最小值(如引用[4]的优化) #### 时间复杂度分析 | 操作 | 时间复杂度 | 说明 | |----------|------------|--------------------------| | `push()` | $O(1)$ | 操作 + 一次比较 | | `pop()` | $O(1)$ | 操作 + 一次比较 | | `top()` | $O(1)$ | 直接访问顶 | | `getMin()`| $O(1)$ | 直接访问 `min_stack` 顶| #### 空间复杂度分析 - **最坏情况**:$O(2n)$(元素严格递减) - **最佳情况**:$O(n)$(元素递增,`min_stack` 仅存首元素) - **平均情况**:显著优于同步压法(引用[1][3]) --- ### 最优解法代码实现(C++) ```cpp class MinStack { private: stack<int> data_stack; // 主数据 stack<int> min_stack; // 最小值辅助 public: MinStack() {} // 初始化 void push(int val) { data_stack.push(val); // 仅当 min_stack 为空或 val ≤ 当前最小值时压 if (min_stack.empty() || val <= min_stack.top()) { min_stack.push(val); } } void pop() { // 若弹出值等于当前最小值,则同步弹出 min_stack if (data_stack.top() == min_stack.top()) { min_stack.pop(); } data_stack.pop(); } int top() { return data_stack.top(); } int getMin() { return min_stack.top(); // 直接返回最小顶 } }; ``` --- ### 演算示例(引用[5]的操作序列) | 操作 | `data_stack` (底→顶) | `min_stack` (底→顶) | 返回值 | 关键逻辑说明 | |------------------|--------------------------|--------------------------|--------|----------------------------------| | `MinStack()` | `[]` | `[]` | | 初始化空 | | `push(-2)` | `[-2]` | `[-2]` | | `min_stack` 压入首个元素 | | `push(0)` | `[-2, 0]` | `[-2]` | | 0 > -2,不压 `min_stack` | | `push(-3)` | `[-2, 0, -3]` | `[-2, -3]` | | -3 < -2,压入 `min_stack` | | `getMin()` | | | **-3** | 访问 `min_stack.top()` | | `pop()` | `[-2, 0]` | `[-2]` | | 弹出 -3 且等于 `min_stack.top()`| | `top()` | | | **0** | 访问 `data_stack.top()` | | `getMin()` | | | **-2** | `min_stack` 顶回退到 -2 | > **关键点**:`pop()` 时仅当弹出值等于 `min_stack.top()` 才同步弹出,避免最小值丢失(如 `push(0)` 后弹出不影响最小值)[^4]。 --- ### 对比其他解法 1. **同步双法(引用[1][3])**: - `min_stack` 始终与 `data_stack` 同大小 - 空间复杂度恒为 $O(2n)$,存在冗余存储 - 实现简单但空间效率低 2. **单元组法(引用[2])**: - 单存储 `(value, current_min)` - 空间复杂度 $O(2n)$,访问逻辑稍复杂 - 无同步问题,但扩展性受限 > **最优解优势**:空间效率显著提升(尤其对递增序列),代码简洁易维护[^4]。 --- ### 边界处理 1. **空操作**: - `pop()`/`top()`/`getMin()` 需检查空(LeetCode 测试用例保证非空) 2. **重复最小值**: ```cpp push(0); // data_stack=[0], min_stack=[0] push(1); // data_stack=[0,1], min_stack=[0] push(0); // data_stack=[0,1,0], min_stack=[0,0] ``` - 使用 `val <= min_stack.top()` 保证重复最小值被压 - `pop()` 时同步弹出避免过早丢失最小值 --- ### 相关问题 1. 如何处理自定义对象的最小? → 需实现比较运算符(如 `operator<=`)[^4]。 2. 为什么 `min_stack` 压条件是 $\leq$ 而非 $<$? → 防止重复最小值场景下 `getMin()` 错误(见边界处理示例)[^5]。 3. 如何扩展支持多维度最小值(如最大值、中位数)? → 设计多维辅助或使用红黑树结构[^2]。 [^1]: 双同步压入法空间效率低 [^2]: 单元组法扩展性受限 [^3]: 同步双法存在冗余存储 [^4]: 非同步压优化空间效率 [^5]: 重复最小值需特殊处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值