常数时间获取栈最小元素:请解析MinStack2的push方法代码逻辑
理解MinStack2的运行逻辑
咱们来一步步拆解这个MinStack2类的设计思路和代码逻辑——它的核心目标是在常数时间O(1)内获取栈中的最小元素,用到了双栈的设计思路,其中一个栈存所有元素,另一个栈存「最小值+出现次数」的配对,避免频繁调整最小值。
初始化方法 __init__
- 这里初始化了两个空列表:
self.stack:用来存储所有入栈的元素,就是普通的栈结构,负责正常的push/pop操作。self.minStack:这个是关键,它里面的每个元素都是一个长度为2的列表[最小值, 出现次数],用来跟踪当前栈中的最小值以及这个最小值出现的次数。
push方法的详细逻辑
push方法负责把元素x压入栈,同时维护minStack的状态,保证它始终能正确反映当前栈的最小值:
- 第一步先把
x压入主栈:self.stack.append(x),这是普通栈的入栈操作。 - 接下来判断
minStack是否为空:- 如果
minStack不为空,分三种情况处理:- 当
x < self.minStack[-1][0]:说明x是当前栈的新最小值,直接把[x, 1]压入minStack,计数初始化为1。 - 当
x == self.minStack[-1][0]:说明当前最小值又出现了一次,不需要压入新元素,只需要把minStack栈顶元素的计数加1(self.minStack[-1][1] += 1)。 - 当
x > self.minStack[-1][0]:这里要注意,你给出的代码里会把[x, 1]压入minStack,但其实这是个冗余操作——因为x比当前最小值大,它永远不会成为当前栈的最小值,正常优化的话这里不需要做任何操作。不过咱们按给定代码的逻辑来,此时会把[x, 1]加入minStack。
- 当
- 如果
minStack为空(也就是第一次入栈):直接把[x, 1]压入minStack即可,因为第一个元素就是当前最小值。
- 如果
举个实际例子
假设我们依次执行push(3)、push(2)、push(2)、push(4):
push(3):主栈变成[3],minStack为空,压入[3,1]→minStack = [[3,1]]push(2):2 < 3,压入[2,1]→minStack = [[3,1], [2,1]]push(2):等于栈顶的2,计数加1 →minStack = [[3,1], [2,2]]push(4):4 > 2,按代码逻辑压入[4,1]→minStack = [[3,1], [2,2], [4,1]]
为什么要存计数?
这个设计的妙处在于处理pop操作时(虽然你没给出pop代码,但逻辑是通的):如果弹出的元素是当前最小值,只需要把minStack栈顶的计数减1;如果计数减到0,再弹出minStack的栈顶元素。这样就能保证minStack的栈顶始终是当前栈的最小值,而且所有操作都是O(1)时间,不会因为频繁弹出最小值而需要遍历栈找新的最小值。
内容的提问来源于stack exchange,提问作者John Asare
相关产品推荐
相关产品推荐

