剑指 Offer 30. 包含min函数的栈

题目描述

        定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.min();   --> 返回 -2.

提示:

  1. 各函数的调用总次数不超过 20000 次

        本题的关键点是如何将min操作的时间复杂度降到O(1),难点在于栈中的元素是动态的,随着元素的出栈,最小值一直在变化。

        为了记录最小值的变化,我们引入另一个辅助栈。在入栈时如果要入栈的值比辅助栈顶的元素更小,那么就同时将这个值压入辅助站中。在出栈时,如果当前出栈的值比辅助栈顶的元素大,那么辅助栈就无须变化,否则就需要将辅助栈顶的元素弹出。

class MinStack(object):

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack=[]
        self.min_num=[]


    def push(self, x):
        """
        :type x: int
        :rtype: None
        """
        self.stack.append(x)
        if len(self.min_num) == 0 or self.min_num[-1]>=x:
            self.min_num.append(x)


    def pop(self):
        """
        :rtype: None
        """
        if self.min_num[-1] == self.stack[-1]:
            self.min_num.pop()
        self.stack.pop()


    def top(self):
        """
        :rtype: int
        """
        return self.stack[-1]


    def min(self):
        """
        :rtype: int
        """
        if len(self.min_num) == 0:
            return None
        return self.min_num[-1]

        上面这种做法是较为容易想到的,还有另一种非常巧妙不引入额外空间的方法,只有一个栈和栈当前最小值的变量,但是比较难理解。

        入栈时首先计算原数值与当前栈中最小值的差值,这个差值如果是正数就表示原数值比较大,直接将差值入栈。如果是负数就表示原数值更小,则差值入栈后要将当前最小值更新为原数值。也就是说栈中保存的是原数值与此前栈中最小值的差值,在差值入栈之后要更新最小值。

入栈(不更新最小值):原数值 - 最小值 = 入栈值

入栈(更新最小值):原数值 - 前最小值 = 入栈值

        要注意公式中的最小值,这个最小值在入栈操作完成后会更新,也就是说入栈值是由入栈前的栈最小值计算得到的,如果入栈操作后更新了最小值,那么入栈值加当前最小值并不等于原数值,因为当前最小值本身就是原数值。

        求栈顶元素时首先判断栈顶入栈值是正数还是负数,如果是正数则表示原数值不是最小值,那么就将最小值与这个差值相加即可。如果是负数则表示这个位置原本的数就是当前最小值,那么就直接返回当前最小值。

原数值还原:原数值 = 最小值 + 入栈值

        出栈时,如果栈顶入栈值是正数 ,那么表示原数值不是最小值,弹出后最小值不会发生变化。如果是负数,那么表示原数值就是栈最小值,将它弹出后要更新最小值。前面说过,如果原数值是最小值,那么入栈的公式是:原数值 - 前最小值 = 入栈值。而入栈后会将最小值更新为原数值。也就是:当前最小值 - 前最小值 = 入栈值,那么我们就可以得到:

最小值还原:前最小值 = 当前最小值 - 入栈值

        这种方法真的很绕,建议自己手动模拟几次入站出站操作,代码如下:

class MinStack(object):

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack=[]
        self.min_num=float('inf')


    def push(self, x):
        """
        :type x: int
        :rtype: None
        """
        if len(self.stack) == 0:
            self.stack.append(0)
            self.min_num=x
        else:
            self.stack.append(x-self.min_num)
            self.min_num=min(x,self.min_num)


    def pop(self):
        """
        :rtype: None
        """
        top=self.stack.pop()
        if top < 0:
            self.min_num-=top


    def top(self):
        """
        :rtype: int
        """
        top=self.stack[-1]
        if top >=0:
            return self.min_num+top
        else:
            return self.min_num

    def min(self):
        """
        :rtype: int
        """
        return self.min_num
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值