155.最小栈
题目描述
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
- MinStack() 初始化堆栈对象。
- void push(int val) 将元素val推入堆栈。
- void pop() 删除堆栈顶部的元素。
- int top() 获取堆栈顶部的元素。
- int getMin() 获取堆栈中的最小元素。
示例
示例 1:
1
2
3
4
5
6
输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
示例 2:
1
2
3
4
5
6
输入:
["MinStack","push","push","getMin","pop","getMin"]
[[],[0],[1],[],[],[]]
输出:
[null,null,null,0,null,0]
提示
- -2^31 <= val <= 2^31 - 1
- pop、top 和 getMin 操作总是在 非空栈 上调用
- push, pop, top 和 getMin 的操作次数最多 3 * 10^4 次
解题思路
- 使用双栈方法实现最小栈
- 主栈正常存储所有元素
- 辅助最小栈同步记录当前状态的最小值
- 每次 push 操作时,同时维护最小栈的状态
- 确保 getMin() 方法能在 O(1) 时间内返回最小元素
Swift 代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class MinStack {
// 主栈,存储所有元素
private var stack: [Int]
// 最小栈,同步记录最小元素
private var minStack: [Int]
// 初始化方法
init() {
stack = []
minStack = []
}
// 入栈操作
func push(_ val: Int) {
// 主栈正常添加元素
stack.append(val)
// 最小栈维护最小值
if minStack.isEmpty || val <= minStack.last! {
minStack.append(val)
}
}
// 出栈操作
func pop() {
// 如果出栈元素是当前最小值,最小栈也需要同步出栈
if let top = stack.last, top == minStack.last {
minStack.removeLast()
}
// 主栈出栈
stack.removeLast()
}
// 获取栈顶元素
func top() -> Int {
return stack.last!
}
// 获取最小元素
func getMin() -> Int {
return minStack.last!
}
}
代码解释:
- 定义两个数组:
stack
(主栈)和minStack
(最小栈) push
方法:- 将元素压入主栈
- 如果最小栈为空或新元素小于等于当前最小值,压入最小栈
pop
方法:- 如果出栈元素等于最小栈栈顶,同时弹出最小栈
- 弹出主栈元素
top
方法:返回主栈栈顶元素getMin
方法:返回最小栈栈顶元素(即当前最小值)
复杂度分析
- 时间复杂度:O(1),所有操作都是常数时间
- 空间复杂度:O(n),需要额外的最小栈存储空间,最坏情况下空间与元素数量成正比
额外说明:
- 这是一种用空间换时间的经典设计模式
- 通过额外的最小栈,实现了 O(1) 获取最小元素
- 适用于需要频繁获取最小元素的场景
- 算法核心在于同步维护最小栈的状态
算法对比
- 单栈实现:需要遍历整个栈,时间复杂度 O(n)
- 本解法(双栈):始终保持 O(1) 时间复杂度
- 适用性:数据量较大时,本解法性能更优
本文由作者按照 CC BY 4.0 进行授权