【Leetcode】716. Max Stack

題目地址:

https://leetcode.com/problems/max-stack/

用棧實現一個數據結構可以實現如下操作:
1、將數據進棧,出棧,並且按照FILO的原則;
2、查看棧頂,查看棧中最大值;
3、刪掉棧中最大值。

基本思路是用兩個棧,其中一個棧s1s_1存原本的數據,另開一個單調棧s2s_2,存所有遇到的最大值。這樣即使在原棧中的最大值pop掉,也能通過在第二個棧裏找到剩餘數字的最大值。具體考慮如下:
1、push的時候,對於s1s_1只需直接進棧即可,對於s2s_2,要看一眼新來的數是否大於等於棧頂,如果是,則進棧,否則不進棧。這樣的考慮在於記錄當前棧中的最大值,注意,即使新來的數等於棧頂,仍然需要進棧,這是爲了記錄這個最大值出現了多少次;
2、pop的時候,對於s1s_1仍然是直接pop,對於s2s_2則需要看一下從s1s_1裏pop的是否是當前最大值,如果是,則將s2s_2也pop,否則不動;
3、top和peekMax就直接看兩個棧的棧頂即可;
4、對於popMax,需要先用一個變量存一下當前最大值是多少,也就是s2s_2的棧頂,然後另外開一個臨時棧,把s1s_1上面的數字全倒進去,直到pop出s1s_1裏的最大值,此時也要pop出s2s_2,然後再調用1裏面的push方法把數字再進棧。注意,一定要調用MaxStack的push方法而不是調用s1s_1的push方法,這是因爲倒出來的數字裏可能有次大值,而那個單調棧只是存放了s1s_1從最大值到棧底的數字裏的最大、次大等等值,並沒有存放最大值到棧頂的數字信息;調用push的目的就是把這些信息也存到s2s_2裏。代碼如下:

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;
    }
}

空間O(n)O(n),時間複雜度只有popMax是O(n)O(n),其餘都是O(1)O(1)

算法正確性證明的關鍵在於,證明s2s_2存放的是s1s_1裏從最大值到棧底的最大、次大等等值,出現次數一樣並且單調遞減排列。可以用數學歸納法,這裏省略。

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