天天看點

劍指--隊列的最大值

劍指–隊列的最大值

1,題目:

劍指--隊列的最大值

2,思路:

看下面的代碼

3,代碼:

寫法一:(隊列+兩個棧):

class MaxQueue {

/*
    等下,我們使用一個隊列正常的存放資料,
    然後使用維護一個單調棧,棧頂為最大值
    再加一個輔助棧

    元素插入順序:1   3   5   5   2   6   1   2

    (棧的元素最左邊為棧底,最右邊為棧頂,隊列也一樣)
    插入 1:
    queue = {1}
    stack = {1}
    插入 3
    queue = {3, 1}
    stack = {3}
    (
        這裡為什麼 stack 是 3?之前的 1 哪去了?
        因為 1 比 3 先插入,是以最先 poll() 的必定會是 1,而在 poll 3 之前,無論 1 是否存在,最大值都會是 3,是以 1 的存在無關緊要
        這裡我們就可以知道,隻要後面進來一個比之前存儲元素都要大的,那麼前面的小元素都無關緊要了,清空棧,隻入棧這個最大元素
    )
    插入 5
    queue = {5, 3, 1}
    stack = {5}
    插入 5
    queue = {5,5, 3, 1}
    stack = {5,5}
    (
        插入跟棧頂元素一樣大的值,這個就不必多說什麼了吧,直接入棧即可
    )
    插入 2
    queue = {2, 5, 5, 3, 1}
    stack = {2, 5, 5}
    (
        這裡為什麼 2 又存在了? 而且是在棧底?
        因為 5 比 2 先插入,是以最先 poll() 的一定會是 5,那麼當 poll 5 的時候,前面的 1 和 3 也都已經 poll() 了
        那麼隊列剩下的就是 5 後面插入元素的最大值,即 2,是以我們需要留下 2
    )
    插入 6
    queue = {6, 2, 5, 5, 3, 1}
    stack = {6}
    插入 1
    queue = {1, 6, 2, 5, 5, 3, 1}
    stack = {1, 6}
    插入 2
    queue = {2, 1, 6, 2, 5, 5, 3, 1}
    stack = {2, 6}
    (
        這裡為什麼是 2 在底部? 1 哪去了?
        6 比 後面的 1 和 2 都先插入,是以在 poll 6 之前, 6 是最大的
        而 1 比 2 先插入,是以在 poll 2 之前,前面的 1 是否存在無關緊要,當 poll 6 後,最大值就會是 6 後面插入元素的最大值。即 2
        這裡我們就知道,我們當插入元素比 棧頂元素 小的時候,我們需要清空掉 棧内所有比 插入元素小的值,然後入棧
        (這裡做法就是 面試題 03.05. 棧排序 的做法)
    )
    */




    Queue<Integer> queue;//隊列
    Deque<Integer> stack;//棧
    Deque<Integer> helper_stack;//輔助棧
    public MaxQueue() {
        queue = new LinkedList<>();
        stack = new LinkedList<>();
        helper_stack = new LinkedList<>();
    }
    
    public int max_value() {
        if(queue.isEmpty()){
            return -1;
        }
        return stack.peek();//傳回最大值
    }
    
    public void push_back(int value) {
        queue.add(value);
        //棧為空,直接入棧
        if(stack.isEmpty()){
            stack.push(value);
        }else{
            if(stack.peek() < value){   //當棧頂元素比目前元素小,那麼清空棧,然後将 value 入棧
                stack.clear();
                stack.push(value);
            }else if(stack.peek() == value){    //當棧頂元素等于目前元素,那麼直接入棧
                stack.push(value);
            }else{
                while(!stack.isEmpty() && stack.peek() >= value){   //當棧頂元素大于目前元素,将大于等于 value 的值壓入輔助棧
                    helper_stack.push(stack.pop());
                }
                //壓入插入元素
                helper_stack.push(value);
                //清空 stack 
                stack.clear();
                //重新将輔助棧的值壓回 stack
                while(!helper_stack.isEmpty()){
                    stack.push(helper_stack.pop());
                }
            }
        }
    }
    
    public int pop_front() {
        if(queue.isEmpty()){
            return -1;
        }
        int temp = queue.poll();
        if(stack.peek() == temp){
            stack.pop();
        }
        return temp;
    }
}

           

寫法二:(隊列+雙端隊列):

class MaxQueue {
    Queue<Integer> que;
    Deque<Integer> deq;

    public MaxQueue() {
        que = new LinkedList<>();  //隊列:插入和删除
        deq = new LinkedList<>();  //雙端隊列:擷取最大值
    }
    
    public int max_value() {
        return deq.size()>0?deq.peek():-1;  //雙端隊列的隊首為que的最大值
    }
    
    public void push_back(int value) {
        que.offer(value);  //value入隊
        while(deq.size()>0 && deq.peekLast()<value){
            deq.pollLast();  //将deq隊尾小于value的元素删掉
        }
        deq.offerLast(value);  //将value放在deq隊尾
    }
    
    public int pop_front() {
        int tmp = que.size()>0?que.poll():-1;  //獲得隊首元素
        if(deq.size()>0 && deq.peek().equals(tmp)){
            deq.poll();  //如果出隊的元素是目前最大值,将deq的隊首出隊
        }
        return tmp;
    }
}


           

寫法三:隊列+雙端連結清單:

public class MaxQueue {

    Queue<Integer> queue;
    LinkedList<Integer> max;
    public MaxQueue() {
        queue = new LinkedList<>();
        max = new LinkedList<>();//LinkedList是雙端連結清單
    }
    
    public int max_value() {
        return max.size()==0?-1:max.getFirst();
    }
    
    public void push_back(int value) {
        queue.add(value);
        while(max.size()!=0&&max.getLast()<value){//注意:這裡第二個判斷條件不能帶等号,即max中對于目前queue中的具有相同值的元素會全部存儲,而不是存儲最近的那個。
            max.removeLast();
        }
        max.add(value);
    }
    
    public int pop_front() {
        if(max.size()!=0&&queue.peek().equals(max.getFirst()))//Integer類型的值的比較不能直接使用==
            max.removeFirst();
        return queue.size()==0?-1:queue.poll();
    }

}