打败算法 —— 最小栈

本文参考

出自LeetCode上的题库 —— 最小栈,根据官方的解法需要额外建立一个辅助栈,本文提出不需要额外空间的解法

https://leetcode-cn.com/problems/min-stack/

最小栈问题

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

示例1:
输入:["MinStack","push","push","push","getMin","pop","top","getMin"]
           [ [], [-2], [0], [-3], [], [], [], [] ]
输出:[ null, null, null, null, -3, null, 0, -2 ]
解释:MinStack minStack = new MinStack();
           minStack.push(-2);
           minStack.push(0);
           minStack.push(-3);
           minStack.getMin(); --> 返回 -3.
           minStack.pop();
           minStack.top(); --> 返回 0.
           minStack.getMin(); --> 返回 -2.

解题思路

一般的栈结构在进行pop操作时,要求将弹出的元素返回,但是本题保证了pop、top 和 getMin 操作总是在非空栈上调用,我们甚至都不需要在top和getMin函数中判断当前的栈是否为空,所以可以很简洁地设计这些基本的栈操作

向栈中压入元素时,官方题解额外用一个辅助栈存储此时的最小值,尽管这种解法非常容易理解,但是除栈本身外,带来了$O(n)$的空间复杂度。因此,为了将空间复杂度降到$O(1)$常数级别,我们仅在栈中存储与当前最小值相比的差值。理解的难度主要在于如何对差值进行处理,例如,在调用top时,如何将差值还原回本身的数值;在调用pop时,如何利用差值更新当前的最小值

差值解法

class MinStack:

  def __init__(self):
    # 模拟栈 

    self.stack = list()
    # 记录最小值 

    self.min_value = -1
    # 栈元素个数计数 

    self.cnt = 0

  # 压栈 

  def push(self, val: int) -> None:
    # 第一个元素 

    if not self.cnt:
      self.stack.append(val)
      self.min_value = val
    else:
      # 栈内存储差值 

      sub = val - self.min_value
      self.stack.append(sub)
      self.min_value = self.min_value if sub > 0 else val
    self.cnt += 1

  # 出栈 

  def pop(self) -> None:
    self.cnt -= 1
    sub = self.stack.pop()
    # 差值 
< 0 更新最小值
    if sub < 0:
      self.min_value -= sub

  # 栈顶 

  def top(self) -> int:
    sub = self.stack[-1]
    if self.cnt > 1:
      # 根据差值还原回原来的数值 

      return self.min_value if sub < 0 else sub + self.min_value
    else:
      # 栈中只有 1 个元素时直接返回 

      return sub

  # 最小值 

  def get_min(self) -> int:
    return self.min_value

posted @ 2022-03-09 19:33  咕~咕咕  阅读(46)  评论(0编辑  收藏  举报