1. 程式人生 > >LeetCode演算法題-Min Stack(Java實現)

LeetCode演算法題-Min Stack(Java實現)

這是悅樂書的第177次更新,第179篇原創

01 看題和準備

今天介紹的是LeetCode演算法題中Easy級別的第36題(順位題號是155)。設計一個支援push,pop,top和在恆定時間內檢索最小元素的堆疊。

push(x) - 將元素x推入堆疊。

pop() - 刪除堆疊頂部的元素。

top() - 獲取頂部元素。

getMin() - 檢索堆疊中的最小元素。

例如:

MinStack minStack = new MinStack();

minStack.push(-2);

minStack.push(0);

minStack.push(-3);

minStack.getMin(); - >返回-3。

minStack.pop();

minStack.top(); - >返回0。

minStack.getMin(); - >返回-2。

本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。

02 第一種解法

利用整型陣列和ArrayList作為棧。

入棧的時候,建立一個容量為2的陣列,陣列第一個元素是要入棧的元素,第二個元素是最小值,將陣列新增到list中。

出棧的時候,獲取list的最後一個元素,並將其移除,此時的最小值是list最後一位元素(陣列)的第二個值。

獲取棧頂,即是list中最後一位元素(陣列)的第一個值。

最小值直接返回最小值即可。

class MinStack {

    private List<int[]> stack ;
    private int min ;

    public MinStack() {
        stack = new ArrayList<int[]>();
    }

    public void push(int x) {
        int[] arr = new int[2];
        arr[0] = x;
        arr[1] = stack.isEmpty() ? x : Math.min(x, min);
        min = arr[1];
        stack.add(arr);
    }

    public void pop() {
        if (!stack.isEmpty()) {
            stack.remove(stack.size()-1);
            min = stack.isEmpty() ? 0 : stack.get(stack.size()-1)[1];
        }
    }

    public int top() {
        return stack.get(stack.size()-1)[0];
    }

    public int getMin() {
        return min;
    }
}


03 第二種解法

此解法使用了棧本身和優先佇列兩種結構,優先佇列是為了解決最小值的問題。

入棧、出棧、棧頂這些操作都可以用棧本身的方法,而最小值則是優先佇列的頭部元素,因為優先佇列自帶排序演算法,在初始化時如果不指定排序方式,則預設以自然方式排序。所以在入棧時,一併也將元素放入優先佇列中,而最小值就是佇列的頭部元素,而其他元素的順序是不是按升序依次排列的,這個還真不一定,但是如果你通過實現Comparable介面,重寫其compareTo方法,可以按照自己定義的方式來排序。

class MinStack2 {
    PriorityQueue<Integer> pQueue = new PriorityQueue<Integer>(); 
    Stack<Integer> stack = new Stack<Integer>();                    

    public MinStack2() {}

    public void push(int x) {
        pQueue.add(x);
        stack.push(x);
    }

    public void pop() {
        int trmp = stack.pop();
        pQueue.remove(trmp);
    }

    public int top() {
        return stack.peek();
    }

    public int getMin() {
        return pQueue.peek();
    }
}


04 第三種解法

使用兩個棧,一個作為正常的棧進行入棧、出棧、獲取棧頂操作,另外一個棧則儲存最小值,每次在第一個棧進行入棧和出棧操作時,都要進行判斷,對第二個棧中的最小值進行相應的操作。

class MinStack3 {
    private Stack<Integer> s1 = new Stack<>();
    private Stack<Integer> s2 = new Stack<>();

    public MinStack3() {}

    public void push(int x) {
        s1.push(x);
        if (s2.isEmpty() || s2.peek() >= x) {
            s2.push(x);
        }
    }

    public void pop() {
        int x = s1.pop();
        if (s2.peek() == x) s2.pop();
    }

    public int top() {
        return s1.peek();
    }

    public int getMin() {
        return s2.peek();
    }
}


05 第四種解法

較之第三種解法,此解法只使用了一個棧來完成入棧、出棧、獲取棧頂和最小值的全部操作。

入棧時,如果新入棧的元素比最小值小,那麼要將舊的最小值入棧,並且新的最小值是此時新入棧的元素,最後再將新元素入棧。

出棧時,如果要移除的元素正好是當前最小值,那麼就需要再出棧一次,並且最小值等於第二次出棧要移除的值,因為入棧時是會將舊的最小值新增進去的,所以出棧時要做此判斷。

class MinStack4 {
    int min = Integer.MAX_VALUE;
    Stack<Integer> stack = new Stack<Integer>();

    public void push(int x) {
        if(x <= min){          
            stack.push(min);
            min = x;
        }
        stack.push(x);
    }

    public void pop() {
        if(stack.pop() == min) {
            min=stack.pop();
        }
    }

    public int top() {
        return stack.peek();
    }

    public int getMin() {
        return min;
    }
}


06 小結

演算法專題目前已連續日更超過一個月,演算法題文章35+篇,公眾號對話方塊回覆【資料結構與演算法】、【演算法】、【資料結構】中的任一關鍵詞,獲取系列文章合集。

以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!