topic

Design a stack that supports push, pop, top operations, and can retrieve the smallest element in constant time.

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

ideas

Auxiliary stack

The title requires that the smallest element can be retrieved in Changshu time. Constant time is O(1) time complexity, so you cannot use for loop to traverse and retrieve, and the time complexity of for loop is O(n)

The idea is to maintain another auxiliary stack minStack, so that the top of the auxiliary stack always saves the smallest element in the current stack

class MinStack:

  def __init__(self):
    # 普通栈
    self.stack = []
    # 辅助栈,初始化给一个无穷大
    self.min_stack = [math.inf]

  def push(self, val: int) -> None:
    # 普通栈正常push
    self.stack.append(val)
    # 辅助栈只push小于等于栈顶的
    self.min_stack.append(min(val,self.min_stack[-1]))

  def pop(self) -> None:
    self.stack.pop()
    self.min_stack.pop()

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

  def getMin(self) -> int:
    return self.min_stack[-1]

Do not use auxiliary stack

The problem can also be solved with just one stack.
The method of assisting the stack is to add a stack to maintain the minimum value.
With only one stack, you only need to add a new variable to hold the minimum value. When the data is pushed into and out of the stack, through some methods, the change of the minimum value is recorded in the data stack.

Method one:
When an element is pushed onto the stack, if the pushed value is smaller than the current minimum value, the variable that holds the minimum value will be updated. The previous minimum value is also pushed into the stack to save, and then a new element is pushed onto the stack.

入栈 3 
|   |   min = 3
|   |     
|_3_|    
stack   

入栈 5 
|   |   min = 3
| 5 |     
|_3_|    
stack  

入栈 2 
| 2 |   min = 2?
| 5 |     
|_3_|    
stack  

入栈2时,栈中最小值变成了2,如果直接将min跟新成2,那之前的最小值3就会丢失

为了保存之前的最小值3,在入栈2时,先将之前最小值3入栈保存在栈中,然后在入栈2,更新min

也就是,当新入栈的值,比之前的最小值还小,就将旧的最小值先保存到栈中,在入栈新的值,并且更新最小值为新入栈的值

| 2 |   min = 2
| 3 |  
| 5 |     
|_3_|    
stack  

入栈 6 
| 6 |  min = 2
| 2 |   
| 3 |  
| 5 |     
|_3_|    
stack  

出栈 6     
| 2 |   min = 2
| 3 |  
| 5 |     
|_3_|    
stack  

出栈 2     
| 2 |   min = 2
| 3 |  
| 5 |     
|_3_|    
stack

出栈时,当前top元素,和当前min值相同时,说明当前top元素,在入栈时是更新了最小值的元素,也就是说它的下一个元素,是之前旧的min值

所以,出栈2,出栈3,同时更新min=3

作者:windliang
链接:https://leetcode-cn.com/problems/min-stack/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-38/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

python code

class MinStack:

    def __init__(self):
        self.stack = []
        self.min = -1

    def push(self, val: int) -> None:
        if not self.stack:
            self.stack.append(val)
            self.min = val
        else:
            # 这里必须用<=,必须也要包含等于
            # 比如依次push 0,1,0,push第3个0时,它等于最小值0,
            # 也需要先插入一个最小值到栈中
            # 如果不这么做,pop 0的时候,0等于最小值,会认为前面的1是之前的最小值
            # 但1只是正常push入栈的元素
            if val <= self.min:
                self.stack.append(self.min)
                self.min = val
            self.stack.append(val)

    def pop(self) -> None:
        top = self.stack.pop()
        # 不要忘记pop后空栈的边界情况 self.stack
        if self.stack and top==self.min:
            self.min=self.stack.pop()
        return top

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

    def getMin(self) -> int:
        return self.min

Method two:
The principle is the same as above, but the operation is slightly different.
When pushing, the value is not directly stored, but the difference between the stored value and the current minimum value.

When pushing:

  • Push value > minimum value, push(Push value - minimum value), the minimum value remains unchanged
  • Push value < minimum value, push(push value - old minimum value), new minimum value becomes push value

When pop:

  • Stack top value > 0, push value = stack top value + minimum value, minimum value remains unchanged
  • stack top value < 0, push value = minimum value, previous minimum value = push value - stack top value = minimum value - stack top value
入栈 3,存入 3 - 3 = 0
|   |   min = 3
|   |     
|_0_|    
stack   

入栈 5,存入 5 - 3 = 2
|   |   min = 3
| 2 |     
|_0_|    
stack  

入栈 2,因为出现了更小的数,所以我们会存入一个负数,这里很关键
也就是存入  2 - 3 = -1, 并且更新 min = 2 
对于之前的 min 值 3, 我们只需要用更新后的 min - 栈顶元素 -1 就可以得到    
| -1|   min = 2
| 5 |     
|_3_|    
stack  

入栈 6,存入  6 - 2 = 4
| 4 |   min = 2
| -1| 
| 5 |     
|_3_|    
stack  

出栈,返回的值就是栈顶元素 4 加上 min,就是 6
|   |   min = 2
| -1| 
| 5 |     
|_3_|    
stack  

出栈,此时栈顶元素是负数,说明之前对 min 值进行了更新。
入栈元素 - min = 栈顶元素,入栈元素其实就是当前的 min 值 2
所以更新前的 min 就等于入栈元素 2 - 栈顶元素(-1) = 3
|   | min = 3
| 5 |     
|_3_|    
stack   

作者:windliang
链接:https://leetcode-cn.com/problems/min-stack/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-38/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。  

python code

class MinStack:

    def __init__(self):
        self.stack = []
        self.min = -1

    def push(self, val: int) -> None:
        if not self.stack :
            self.min = val
        diff = val - self.min
        self.stack.append(diff)
        if diff < 0:
            self.min = val

    def pop(self) -> None:
        diff = self.stack.pop()
        if diff < 0:
            top = self.min
            old_min = top - diff
            self.min = old_min
        else:
            top = self.min + diff
        
        return top

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

    def getMin(self) -> int:
        return self.min

Ethan
140 声望11 粉丝

水平较低,只是记录,谨慎参阅


引用和评论

0 条评论