題目地址:
https://leetcode.com/problems/max-stack/
用棧實現一個數據結構可以實現如下操作:
1、將數據進棧,出棧,並且按照FILO的原則;
2、查看棧頂,查看棧中最大值;
3、刪掉棧中最大值。
基本思路是用兩個棧,其中一個棧存原本的數據,另開一個單調棧,存所有遇到的最大值。這樣即使在原棧中的最大值pop掉,也能通過在第二個棧裏找到剩餘數字的最大值。具體考慮如下:
1、push的時候,對於只需直接進棧即可,對於,要看一眼新來的數是否大於等於棧頂,如果是,則進棧,否則不進棧。這樣的考慮在於記錄當前棧中的最大值,注意,即使新來的數等於棧頂,仍然需要進棧,這是爲了記錄這個最大值出現了多少次;
2、pop的時候,對於仍然是直接pop,對於則需要看一下從裏pop的是否是當前最大值,如果是,則將也pop,否則不動;
3、top和peekMax就直接看兩個棧的棧頂即可;
4、對於popMax,需要先用一個變量存一下當前最大值是多少,也就是的棧頂,然後另外開一個臨時棧,把上面的數字全倒進去,直到pop出裏的最大值,此時也要pop出,然後再調用1裏面的push方法把數字再進棧。注意,一定要調用MaxStack的push方法而不是調用的push方法,這是因爲倒出來的數字裏可能有次大值,而那個單調棧只是存放了從最大值到棧底的數字裏的最大、次大等等值,並沒有存放最大值到棧頂的數字信息;調用push的目的就是把這些信息也存到裏。代碼如下:
import java.util.ArrayDeque;
import java.util.Deque;
public class MaxStack {
Deque<Integer> stk, maxStk;
public MaxStack() {
stk = new ArrayDeque<>();
maxStk = new ArrayDeque<>();
}
public void push(int x) {
stk.push(x);
if (maxStk.isEmpty() || maxStk.peek() <= x) {
maxStk.push(x);
}
}
public int pop() {
int x = stk.pop();
if (!maxStk.isEmpty() && x == maxStk.peek()) {
maxStk.pop();
}
return x;
}
public int top() {
return stk.peek();
}
public int peekMax() {
return maxStk.peek();
}
public int popMax() {
Deque<Integer> tempStk = new ArrayDeque<>();
int x = maxStk.pop();
while (!stk.isEmpty() && stk.peek() < x) {
tempStk.push(stk.pop());
}
stk.pop();
while (!tempStk.isEmpty()) {
// 調用MaxStack的push方法,把倒出來的數字再倒回去
push(tempStk.pop());
}
return x;
}
}
空間,時間複雜度只有popMax是,其餘都是。
算法正確性證明的關鍵在於,證明存放的是裏從最大值到棧底的最大、次大等等值,出現次數一樣並且單調遞減排列。可以用數學歸納法,這裏省略。