今天是2020年5月12日,星期二,也有好幾天沒寫每日一題,繼續撿起來了。
題目描述
設計一個支持 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 操作總是在 非空棧 上調用。
題目分析
本題目屬於一道設計類型的題目,在校招的面試中還是一道比較常見的問題。設計一個最小棧,並要push、pop、top等操作的時間爲一個常數時間。
小編在實現時採用了數據棧和輔助棧數據不同步的方式進行實現。每次push數據時,向數據棧中添加數據,並把當前數據與輔助棧棧頂數據大小進行比較,若x <= minStack.peek(),則需要把當前數據加入輔助棧中。這裏是極需要注意的。在top則藉助站的peek()方法實現即可。
學習weiwei大佬的題解「使用輔助棧(同步和不同步,Python 代碼、Java 代碼)」,數據棧和輔助棧的數據同步,編碼較爲簡單,不需要考慮一些邊界情況,但是可能會存在一些不必要的元素。
參考代碼
- 數據棧和複製棧數據不同方式
class MinStack {
/**
* 用於存儲當前的最小值,棧頂爲當前的最小值
*/
private Stack<Integer> minStack;
private Stack<Integer> valueStack;
public MinStack() {
minStack = new Stack<>();
valueStack = new Stack<>();
}
public void push(int x) {
valueStack.push(x);
if (!minStack.isEmpty()) {
int min = minStack.peek();
if (x <= min) {
minStack.push(x);
}
} else {
minStack.push(x);
}
}
public void pop() {
if (valueStack.isEmpty()) {
return;
}
Integer pop = valueStack.pop();
if (minStack.peek().equals(pop)) {
minStack.pop();
}
}
public int top() {
return valueStack.peek();
}
public int getMin() {
return minStack.peek();
}
public static void main(String[] args) {
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
System.out.println(minStack.getMin());
minStack.pop();
System.out.println(minStack.top());
System.out.println(minStack.getMin());
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
- 數據棧和輔助棧的數據同步
public class MinStack {
// 數據棧
private Stack<Integer> data;
// 輔助棧
private Stack<Integer> helper;
/**
* initialize your data structure here.
*/
public MinStack() {
data = new Stack<>();
helper = new Stack<>();
}
// 思路 1:數據棧和輔助棧在任何時候都同步
public void push(int x) {
// 數據棧和輔助棧一定會增加元素
data.add(x);
if (helper.isEmpty() || helper.peek() >= x) {
helper.add(x);
} else {
helper.add(helper.peek());
}
}
public void pop() {
// 兩個棧都得 pop
if (!data.isEmpty()) {
helper.pop();
data.pop();
}
}
public int top() {
if (!data.isEmpty()) {
return data.peek();
}
throw new RuntimeException("棧中元素爲空,此操作非法");
}
public int getMin() {
if (!helper.isEmpty()) {
return helper.peek();
}
throw new RuntimeException("棧中元素爲空,此操作非法");
}
}
複雜度分析
- 時間複雜度:對於題目中的操作,時間複雜度均爲O(1)。
- 空間複雜度:O(n),n爲總的操作數。在最壞的情況下,我們會連續插入n個元素,此時兩個棧佔用的空間爲O(n)。