2021/5/16 刷题笔记最小栈与辅助栈思想

Posted 黑黑白白君

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021/5/16 刷题笔记最小栈与辅助栈思想相关的知识,希望对你有一定的参考价值。



最小栈

【题目】

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

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


示例:

  • 输入: [“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、top 和 getMin 操作总是在 非空栈 上调用。


来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/min-stack
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

【我的方法】

  • 考虑到要在常数时间内检索到最小元素,意味不能在getMin进行计算,而是在push和pop里面计算得到最小元素。
  • 所以决定以空间换时间,创建另外一个list来存储栈底到当前位置的最小值。
class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        self.minN = []  #栈底到当前位置最小值


    def push(self, val: int) -> None:
        if not self.minN:
            self.minN.append(val)
        elif self.minN[-1]>val:
            self.minN.append(val)
        else:
            self.minN.append(self.minN[-1])
        self.stack.append(val)

    def pop(self) -> None:
        self.stack = self.stack[:-1]
        self.minN = self.minN[:-1]

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

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


# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

执行结果:

  • 执行用时:60 ms, 在所有 Python3 提交中击败了92.38%的用户
  • 内存消耗:17.9 MB, 在所有 Python3 提交中击败了77.53%的用户


辅助栈思想

以空间换时间的情况下,使用辅助栈是常见的做法。在代码实现的时候有两种方式。

1、辅助栈和数据栈同步

  • 特点:编码简单,不用考虑一些边界情况。
  • 缺点:辅助栈可能会存一些“不必要”的元素。

参考代码:

class MinStack:

    # 辅助栈和数据栈同步
    # 思路简单不容易出错

    def __init__(self):
        # 数据栈
        self.data = []
        # 辅助栈
        self.helper = []

    def push(self, x):
        self.data.append(x)
        if len(self.helper) == 0 or x <= self.helper[-1]:
            self.helper.append(x)
        else:
            self.helper.append(self.helper[-1])

    def pop(self):
        if self.data:
            self.helper.pop()
            return self.data.pop()

    def top(self):
        if self.data:
            return self.data[-1]

    def getMin(self):
        if self.helper:
            return self.helper[-1]

复杂度分析:

  • 时间复杂度

    O(1)。“出栈”、“入栈”、“查看栈顶元素”的操作不论数据规模多大,都只是有限个步骤,因此时间复杂度是:O(1)。
  • 空间复杂度

    O(N),这里 N 是读出的数据的个数。

2、辅助栈和数据栈不同步

  • 特点:在“辅助栈和数据栈同步”思想的基础上做一些“优化”,但是在编码上就要注意一些边界条件。
    • 辅助栈为空的时候,必须放入新进来的数。
    • 新来的数小于或者等于辅助栈栈顶元素的时候,才放入,特别注意这里等于要考虑进去,因为出栈的时候,连续的、相等的并且是最小值的元素要同步出栈。
    • 出栈的时候,辅助栈的栈顶元素等于数据栈的栈顶元素,才出栈。

即出栈时,最小值出栈才同步;
入栈时,最小值入栈才同步。

虽然减少了一些空间,但是在“出栈”、“入栈”的时候还要做判断,也有性能上的消耗。

参考代码:

    # 辅助栈和数据栈不同步
    # 关键 1:辅助栈的元素空的时候,必须放入新进来的数
    # 关键 2:新来的数小于或者等于辅助栈栈顶元素的时候,才放入(特别注意这里等于要考虑进去)
    # 关键 3:出栈的时候,辅助栈的栈顶元素等于数据栈的栈顶元素,才出栈,即"出栈保持同步"就可以了

    def __init__(self):
        # 数据栈
        self.data = []
        # 辅助栈
        self.helper = []

    def push(self, x):
        self.data.append(x)
        # 关键 1 和关键 2
        if len(self.helper) == 0 or x <= self.helper[-1]:
            self.helper.append(x)

    def pop(self):
        # 关键 3:【注意】不论怎么样,数据栈都要 pop 出元素
        top = self.data.pop()

        if self.helper and top == self.helper[-1]:
            self.helper.pop()
        return top

    def top(self):
        if self.data:
            return self.data[-1]

    def getMin(self):
        if self.helper:
            return self.helper[-1]

复杂度分析:

  • 时间复杂度

    O(1),“出栈”、“入栈”、“查看栈顶元素”的操作不论数据规模多大,都只有有限个步骤,因此时间复杂度是:O(1)。
  • 空间复杂度

    O(N),这里 N 是读出的数据的个数。


【部分内容参考自】

  • 使用辅助栈(同步和不同步,Python 代码、Java 代码):https://leetcode-cn.com/problems/min-stack/solution/shi-yong-fu-zhu-zhan-tong-bu-he-bu-tong-bu-python-/

以上是关于2021/5/16 刷题笔记最小栈与辅助栈思想的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode刷题笔记-数据结构-day14

数据结构学习笔记(特殊的线性表:栈与队列)

小猪的数据结构辅助教程——3.1 栈与队列中的顺序栈

LeetCode Java刷题笔记—155. 最小栈

刷题记录 leetcode155:最小值栈

剑指offer 21:包含min函数的栈