題目描述
- 【問題:】
實現一個特殊的棧,在實現棧的基本功能上,再實現返回棧中的最小元素。 - 【要求:】
- pop(),push(),getMin()時間複雜度都爲 O(1);
- 設計的棧類型可以使用可以使用現成的棧結構。
- 【解答:】
在設計上可以考慮使用兩個棧,一個存放數據的棧稱爲 dataStack ;另一個存放數據棧中的最小值稱爲 minStack ;具體有兩種實現方式。
實現方案一
【算法描述】
- 入棧規則
- 假設當前入棧數據爲 newData ,先將其壓入 dataStack ,然後判斷 minStack 是否爲空;
- 如果爲空,則把 newData 壓入 minStack ;
- 如果不爲空,則比較 newData 與 minStack 的棧頂元素哪一個更小;
- 如果 newData 更小或者兩者相等,則將 newData 壓入 minStack ;
- 如果 minStack 中棧頂元素更小,則把 minStack 棧頂元素重複壓入 minStack 棧頂。
【舉個栗子】
依次入棧3、4、5、1、2、1的過程中,dataStack 和 minStack 變化如圖所示:
-
出棧規則
在 dataStack 彈出棧頂數據記爲 value ,minStack 也對應彈出棧頂元素。返回value。 -
獲取當前棧中的最小值操作
由上述描述可知,minStack 棧中的棧頂元素始終記錄着 dataStack 棧的最小值,所以只需返回 minStack 的棧頂元素即可。
1import java.util.Stack;
2
3public class MyStack1 {
4 private Stack<Integer> dataStack;
5 private Stack<Integer> minStack;
6
7 public MyStack1() {
8 dataStack = new Stack<Integer>();
9 minStack = new Stack<Integer>();
10 }
11
12 //入棧
13 public void push(int newData) {
14 dataStack.push(newData);
15 if(this.minStack.isEmpty() || newData < this.getMin()) {
16 minStack.push(newData);
17 } else {
18 minStack.push(this.minStack.peek());
19 }
20 }
21
22 //出棧
23 public int pop() {
24 if (dataStack.isEmpty()) {
25 throw new RuntimeException("Your Stack is empty!");
26 }
27 this.minStack.pop();
28 return this.dataStack.pop();
29 }
30
31 //獲得棧中的最小值
32 public int getMin() {
33 if(this.minStack.isEmpty()) {
34 throw new RuntimeException("Your minStack is empty!");
35 }
36 return this.minStack.peek();
37 }
38
39}
時間複雜度爲 O(1),空間複雜度爲 O(n),用於 minStack 的空間開銷
能否設計空間複雜度更優的算法呢?請看實現方案二。
實現方案二
【算法描述】
- 入棧規則
- 假設當前入棧數據爲 newData ,先將其壓入 dataStack ,然後判斷 minStack 是否爲空;
- 如果爲空,則把 newData 壓入 minStack ;
- 如果不爲空,則比較 newData 與 minStack 的棧頂元素哪一個更小;
- 如果 newData 更小或者與 newData 相等,則將 newData 壓入 minStack ;
- 如果 minStack 中棧頂元素更小,則 minStack 不壓入任何內容。
【舉個栗子】
依次入棧3、4、5、1、2、1的過程中,dataStack 和 minStack 變化如圖所示:
- 出棧規則
- 在 dataStack 彈出棧頂數據記爲 value ,然後比較當前 minStack 的棧頂元素和 value 哪一個更小。
- 由上文的入棧規則可知,minStack 的棧頂元素既是 minStack 棧的最小元素,也是當前 dataStack 棧中的最小元素,因此 value 只可能大於或等於 minStack 的棧頂元素,不會出現 value 小於 minStack 的棧頂元素。
- 當 value 等於 minStack 的棧頂元素,則彈出 minStack 中的棧頂元素,當 value 大於 minStack 元素的棧頂元素,minStack 不彈出棧頂元素,組後返回 value。
- 獲取當前棧中的最小值操作
由上述描述可知,minStack 棧中的棧頂元素始終記錄着 dataStack 棧的最小值,所以只需返回 minStack 的棧頂元素即可。
1public class MyStack2 {
2 private Stack<Integer> dataStack;
3 private Stack<Integer> minStack;
4
5 public MyStack2() {
6 dataStack = new Stack<Integer>();
7 minStack = new Stack<Integer>();
8 }
9
10 //入棧
11 public void push(int newData) {
12 dataStack.push(newData);
13 if(minStack.isEmpty() || newData <= this.getMin()) {
14 minStack.push(newData);
15 }
16 }
17
18 //出棧
19 public int pop() {
20 if (dataStack.isEmpty()) {
21 throw new RuntimeException("Your Stack is empty!");
22 }
23 int value = this.dataStack.peek();
24 if(value == this.getMin()) {
25 this.minStack.pop();
26 }
27 return value;
28 }
29
30 //獲取棧中最小值
31 public int getMin() {
32 if(this.minStack.isEmpty()) {
33 throw new RuntimeException("Your Stack is empty!");
34 }
35 return minStack.peek();
36 }
37}
時間複雜度爲 O(1),空間複雜度爲 O(n),用於 minStack 的開銷。
優化點:當算法運行過程中很少遇到“新的最小值或相等”情況時,,該算法的空間利用效率將大大改善!