剑指offer-包含min函数的栈

本文探讨了在栈数据结构中实现O(1)时间复杂度的min函数的方法。介绍了两种思路,一种使用额外变量记录最小值,但在元素变化时需重新遍历栈;另一种引入辅助栈存储最小值,虽增加空间复杂度,但实现了常数时间获取最小值的目标。最后,提出了一种优化方案,使用辅助栈存储最小值的索引,既保持了时间复杂度,又减少了空间占用。

题目:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

思路一:利用一个变量min,每次push时,比较push的值和min的值,若push值小于min的值则将min值进行更新。

思路一分析:该方法可以获得当前栈的最小值,但若最小值被pop出去后,想重新获得最小值则需要重新遍历栈内元素,再更新最小值了。所以这个方法的时间复杂度为O(n),空间复杂度为O(1)。

 

思路二:申请一个辅助栈mins,mins中保存最小值,当push的值小于mins的栈顶元素时,将push值同时压入mins和元数据栈。当push值大于mins的栈顶元素时,将push值压入元数据栈,将mins栈顶元素再次压入mins栈。

思路二分析,该方法的时间复杂度降到了O(1),但是空间复杂度为O(n)。

 

算法优化:

由此可以看出辅助栈中有大量重复的值,这点可以进行优化。可以在push时判断一下,如果比最小值还大,那么就不加入辅助栈。pop时如果要pop的数据不等于辅助栈栈顶元素,则辅助栈的栈顶就不出栈。如下图所示:

上述方法的问题在于如果要push一个和最小值相同的数进栈则辅助栈和元数据栈中都要push。否则最小值出栈后下一个最小值就不对了。如下图所示

 

 

针对上述问题的优化思路:在mins栈中保存最小值的索引。如下图所示

 

 最终代码:

import java.util.ArrayList;
import java.util.List;

/**
 * @author xiaoshi on 2018/9/1.
 */
public class MinStack {

    private List<Integer> data = new ArrayList<Integer>();
    private List<Integer> mins = new ArrayList<Integer>();

    public void push(int num) throws Exception {
        data.add(num);
        if(mins.size() == 0) {
            // 初始化mins
            mins.add(0);
        } else {
            // 辅助栈mins push最小值的索引
            int min = getMin();
            if (num < min) {
                mins.add(data.size() - 1);
            }
        }
    }

    public int pop() throws Exception {
        // 栈空,抛出异常
        if(data.size() == 0) {
            throw new Exception("栈为空");
        }
        // pop时先获取索引
        int popIndex = data.size() - 1;
        // 获取mins栈顶元素,它是最小值索引
        int minIndex = mins.get(mins.size() - 1);
        // 如果pop出去的索引就是最小值索引,mins才出栈
        if(popIndex == minIndex) {
            mins.remove(mins.size() - 1);
        }
        return data.remove(data.size() - 1);
    }

    public int getMin() throws Exception {
        // 栈空,抛出异常
        if(data.size() == 0) {
            throw new Exception("栈为空");
        }
        // 获取mins栈顶元素,它是最小值索引
        int minIndex = mins.get(mins.size() - 1);
        return data.get(minIndex);
    }

}

 

转载于:https://www.cnblogs.com/April1995/p/9600289.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值