設計一個具有 getMin 功能的棧,看這裏!

題目描述

  • 【問題:】
    實現一個特殊的棧,在實現棧的基本功能上,再實現返回棧中的最小元素。
  • 【要求:】
  1. pop(),push(),getMin()時間複雜度都爲 O(1);
  2. 設計的棧類型可以使用可以使用現成的棧結構。
  • 【解答:】
    在設計上可以考慮使用兩個棧,一個存放數據的棧稱爲 dataStack ;另一個存放數據棧中的最小值稱爲 minStack ;具體有兩種實現方式。

實現方案一

【算法描述】

  • 入棧規則
  1. 假設當前入棧數據爲 newData ,先將其壓入 dataStack ,然後判斷 minStack 是否爲空;
  2. 如果爲空,則把 newData 壓入 minStack ;
  3. 如果不爲空,則比較 newData 與 minStack 的棧頂元素哪一個更小;
  4. 如果 newData 更小或者兩者相等,則將 newData 壓入 minStack ;
  5. 如果 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 的空間開銷
能否設計空間複雜度更優的算法呢?請看實現方案二。

實現方案二

【算法描述】

  • 入棧規則
  1. 假設當前入棧數據爲 newData ,先將其壓入 dataStack ,然後判斷 minStack 是否爲空;
  2. 如果爲空,則把 newData 壓入 minStack ;
  3. 如果不爲空,則比較 newData 與 minStack 的棧頂元素哪一個更小;
  4. 如果 newData 更小或者與 newData 相等,則將 newData 壓入 minStack ;
  5. 如果 minStack 中棧頂元素更小,則 minStack 不壓入任何內容。

【舉個栗子】
依次入棧3、4、5、1、2、1的過程中,dataStack 和 minStack 變化如圖所示:

  • 出棧規則
  1. 在 dataStack 彈出棧頂數據記爲 value ,然後比較當前 minStack 的棧頂元素和 value 哪一個更小。
  2. 由上文的入棧規則可知,minStack 的棧頂元素既是 minStack 棧的最小元素,也是當前 dataStack 棧中的最小元素,因此 value 只可能大於或等於 minStack 的棧頂元素,不會出現 value 小於 minStack 的棧頂元素。
  3. 當 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 的開銷。
優化點:當算法運行過程中很少遇到“新的最小值或相等”情況時,,該算法的空間利用效率將大大改善!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章