1. 程式人生 > >棧和佇列常見題型(java版)

棧和佇列常見題型(java版)

直接上乾貨。。。。。

棧和佇列常見題型:

  1. 實現棧和實現佇列。
  2. 兩個棧實現一個佇列。
  3. 設計棧,使得pop,push和min時間複雜度為O(1)。
  4. 滑動視窗的最大值。
  5. 棧的進出序列。

實現棧和實現佇列

主要包括:棧,佇列,迴圈佇列。


package com.sywyg;

/**
 * 實現棧
 * 陣列應該是Object型別的
 * 注意top的設定影響出棧和獲取棧頂元素。
 * size也可以用top代替
 */
class MyStack<E>{
    // 棧元素個數
    private int size;
    // 棧頭
    private int top;
    // 陣列儲存元素
private Object[] stack = null; public MyStack(int length){ stack = new Object[length]; top = 0; } public int size(){ return size; } // 進棧 public void push(E e){ if(size == stack.length){ try{ throw new Exception("棧已滿"
); }catch(Exception ex){ ex.printStackTrace(); } } stack[top++] = e; size++; } // 出棧 public E pop(){ E e = null; if(size == 0){ try{ throw new Exception("棧為空"); }catch(Exception ex){ ex.printStackTrace(); } } e = (E)stack[--top]; size--; return
e; } // 獲取棧頂元素 public E top(){ if(size == 0){ try{ throw new Exception("棧為空"); }catch(Exception e){ e.printStackTrace(); } } return (E)stack[top-1]; } } /** * 建立佇列,這種佇列會造成假溢位 */ class MyQueue<E>{ // 佇列長度 private int size; // 隊頭 private int front; // 隊尾 private int back; private Object[] queue; public MyQueue(int length){ queue = new Object[length]; size = 0; front = 0; back = 0; } public int size(){ return size; } // 進隊 public void enqueue(E e){ if(size == queue.length){ try{ throw new Exception("隊已滿"); }catch(Exception ex){ ex.printStackTrace(); } } queue[back++] = e; size++; } // 出隊 public E dequeue(){ E e = null; if(size == 0 || back == front){ try{ throw new Exception("隊為空"); }catch(Exception ex){ ex.printStackTrace(); } } e = (E)queue[front++]; size--; return e; } // 返回隊頭 public E front(){ return (E)queue[front]; } // 返回隊尾? public E back(){ return (E)queue[back - 1]; } } /** * 迴圈佇列,採用浪費一個位置(使用size可以保證全利用) * 這裡不使用size標記佇列的長度,儘管這種方式很簡單 */ class LoopQueue<E>{ // 隊頭 private int front; // 隊尾 private int back; private Object[] queue; public LoopQueue(int length){ // 浪費一個 queue = new Object[length + 1]; front = 0; back = 0; } public int size(){ return (back - front + queue.length)% queue.length; } // 進隊 public void enqueue(E e){ if((front - back + queue.length)% queue.length == 1){ try{ throw new Exception("隊已滿"); }catch(Exception ex){ ex.printStackTrace(); } } queue[back ++ % queue.length] = e; } // 出隊 public E dequeue(){ E e = null; if(front == back){ try{ throw new Exception("隊為空"); }catch(Exception ex){ ex.printStackTrace(); } } e = (E)queue[front++ % queue.length]; return e; } // 返回隊頭 public E front(){ return (E)queue[front]; } // 返回隊尾? public E back(){ return (E)queue[(back - 1 + queue.length) % queue.length]; } }

兩個棧實現一個佇列

思想:一個棧A只進,一個棧B只出,B為空則A元素進入B,再出棧。


package com.sywyg;

/**
 * 兩個棧實現一個佇列。
 * 這樣仍然會造成假溢位。
 * 
 *
 */
    public static class Solution<E>{
        // 應該在構造器中賦值。
        // stack1用來入隊
        private Stack<E> stack1 = new Stack<E>();
        // stack2用來出隊
        private Stack<E> stack2 = new Stack<E>();

        // 入隊
        public void enqueue(E e){
            stack1.push(e);
            //System.out.println("此時stack1棧頂元素為:" + stack1.top());
        }

        // 出隊
        public E dequeue(){
            E e = null;
            if(stack2.size() != 0){
                e = stack2.pop();
            }else if(stack1.size() != 0){
                int length = stack1.size();
                for(int i = 0;i<length;i++){
                    stack2.push(stack1.pop());
                    //System.out.println("此時stack2棧頂元素為:" + stack2.top());
                }
                e = stack2.pop();
            }
            return e;
        }
}

- 測試:進進出出,進出。
- 如何用兩個佇列實現一個棧。

#設計棧,使得pop,push和min時間複雜度為O(1)

思想:額外的棧A存放當前最小值,每當進來的值a小於/等於該棧頂值b時,a需要入棧A;出棧時若棧A的棧頂和剛出棧的元素相等時,則A也出棧。

```java

package com.sywyg;
import java.util.Stack;

/**
 * 設計棧,使得pop,push和min時間複雜度為O(1)。
 * 或者使用一個每個最小值再包含一個計數標記
 */
    public static class Solution<E>{
        private Stack<E> stack,stackMin;
        public Solution(){
            stack = new Stack<E>();
            stackMin = new Stack<E>();
        }
        // 入棧
        public void push(E e){
            stack.push(e);
            if(stackMin.isEmpty()){
                stackMin.push(e);
            }else if(stackMin.peek() >= e){
                stackMin.push(e);
            }
        }
        // 出棧
        public E pop(){
            E e = stack.pop();
            if(e == stackMin.peek()){
                stackMin.pop();
            }

        }
        // 返回最小
        public E min(){
            return stackMin.peek();
        }
}





<div class="se-preview-section-delimiter"></div>
  • 測試:小大大大小小,每次出棧判斷是否正確。
  • 時間複雜度:O(1),空間複雜度O(n)

滑動視窗的最大值

給定一個數組,和滑動視窗的大小,計算每個視窗中的最大值。例如陣列{1,2,3,4,5},視窗大小為3。那麼共存在3個滑動視窗,它們的大小為:{3,4,5}。

思想:須用到上面的第2題和第3題,用兩個能夠O(1)時間內計算出最大值的棧實現佇列。先進入3個(視窗大小),然後再依次進1出1個。在統計最大值的時候比較兩個棧中的最大值即可,注意需要判斷棧是否為空。


package com.sywyg;

import java.util.Stack;

/**
 * 滑動視窗的最大值。
 * @author sywyg
 * 測試
 */
public class Question4 {

    public static void main(String[] args) {
        int[] array = {2,3,4,2,6,5,2,1};
        int[] max = solution(array, 3);
        for (int i = 0; i < max.length; i++) {
            System.out.println(max[i]);
        }
    }


    public static int[] solution(int[] array,int size){
        int[] max = new int[array.length - size + 1];
        MyQueue<Integer> queue = new MyQueue<Integer>(); 
        int i = 0;
        for(i = 0; i<size; i++){
            queue.enqueue(array[i]);
        }
        int j = 0;
        // 先進一個
        max[j++] = queue.stack1.max();
        for(;i<array.length;i++){
            queue.dequeue();
            queue.enqueue(array[i]);
            // 兩個棧中的最大值進行比較
            if(queue.stack2.stackMax.size() == 0 || queue.stack1.max() >= queue.stack2.max()){
                max[j++] = queue.stack1.max();
            }else
                max[j++] = queue.stack2.max();
        }
        return max;
    }

    /**
     * 兩個棧實現佇列
     */
    public static class MyQueue<E>{
        // 應該在構造器中賦值。
        // stack1用來入隊
        public MyStack<E> stack1 = new MyStack<E>();
        // stack2用來出隊
        public MyStack<E> stack2 = new MyStack<E>();

        // 入隊
        public void enqueue(E e){
            stack1.push(e);
            //System.out.println("此時stack1棧頂元素為:" + stack1.top());
        }

        // 出隊
        public E dequeue(){
            E e = null;
            if(stack2.size() != 0){
                e = stack2.pop();
            }else if(stack1.size() != 0){
                int length = stack1.size();
                for(int i = 0;i<length;i++){
                    stack2.push(stack1.pop());
                    //System.out.println("此時stack2棧頂元素為:" + stack2.top());
                }
                e = stack2.pop();
            }
            return e;
        }
    }
    /**
     * pop(),push(),max() 複雜度為O(1)
     */
    public static class MyStack<E>{
        public Stack<E> stack,stackMax;
        public MyStack(){
            stack = new Stack<E>();
            stackMax = new Stack<E>();
        }
        // 入棧
        public void push(E e){
            stack.push(e);
            if(stackMax.isEmpty()){
                stackMax.push(e);
            }else if((Integer)stackMax.peek() <= (Integer)e){
                stackMax.push(e);
            }
        }
        // 出棧
        public E pop(){
            E e = stack.pop();
            if(e == stackMax.peek()){
                stackMax.pop();
            }
            return e;
        }
        // 返回最大
        public E max(){
            return stackMax.peek();
        }

        public E peek(){

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

}





<div class="se-preview-section-delimiter"></div>
  • 測試:有大有小的輸入。
  • 時間複雜度:O(n)

棧的進出序列

輸入進棧的順序判斷給出的出棧順序是否正確。

思想:先進棧,然後判斷是否和給出的順序相等。若不相等則繼續進棧判斷,直到進完;若相等則繼續出棧判斷,直到出完。


package com.sywyg;

import java.util.Stack;

/**
 * 棧的進出序列
 * @author sywyg
 * @since 2015.7.25
 * 測試:
 */
public class Question5 {

    public static void main(String[] args) {
        Question5 question = new Question5();
        int[] array1 = {1,2,3,4,7};
        int[] array2 = {3,1,2,5,0};
        System.out.println(question.solution(array1, array2));
    }

    // 第一個引數為輸入順序,第二個引數為要判斷的輸出結果
    public boolean solution(int[] array1,int[] array2){
        // 健壯性判斷
        if(array1 == null || array2 == null) return false;
        if(array1.length != array2.length) return false;

        Stack<Integer> stack = new Stack<Integer>();
        int i = 0,j = 0;
        for (; i < array1.length; i++) {
            stack.push(array1[i]);
            while(stack.size() != 0 && stack.peek() == array2[j]) {
                stack.pop();
                j++;
            }
        }
        return j == i?true:false;
    }

}
  • 測試:給出正確的,給出錯誤的,給出不相等的陣列。
  • 時間複雜度:O(n)