1. 程式人生 > >程式設計師程式碼面試指南 —— 棧和佇列(一)

程式設計師程式碼面試指南 —— 棧和佇列(一)

注:題目來自於《程式設計師程式碼面試指南:IT名企演算法與資料結構題目最優解》,該書是左程雲老師的著作,值得推薦,這裡僅是記錄一下該書中題目的解法和個人理解

一:設計一個有getMin功能的棧
  題目:在實現棧的基本功能的基礎上,再實現返回棧中的最小元素操作
  思路:可以建立一個輔助棧,輔助棧保證棧頂值既為最小值。
     當入棧的元素小於輔助棧棧頂值,則輔助棧和資料棧都進行入棧操作。
     當入棧的元素大於輔助棧棧頂值,則資料棧進行入棧操作輔助棧將棧頂元素複製一份,再將該元素進行入棧
  圖解:
  在這裡插入圖片描述
程式碼:

class MyStack {
  private Stack<Integer> stackData;
  private Stack<Integer> stackMin;

  public MyStack() {
    stackData = new Stack<>();
    stackMin = new Stack<>();
  }

  public void push(int num) {
    if (stackMin.isEmpty()) {
      stackMin.push(num);
    } else if (num < getMin()) {
      stackMin.push(num);
    } else {
      int c = stackMin.peek();
      stackMin.push(c);
    }
    stackData.push(num);
  }

  public int pop() {
    if (stackData.isEmpty()) {
      throw new RuntimeException("stack is empty");
    } else {
      stackMin.pop();
      return stackData.pop();
    }
  }

  public int getMin() {
    if (stackMin.isEmpty()) {
      throw new RuntimeException("stack is empty");
    } else {
      return stackMin.peek();
    }
  }
}

測試方法:

public class GetMinStack {
  public static void main(String[] args) {
    MyStack stack = new MyStack();
    stack.push(4);
    stack.push(3);
    stack.push(4);
    stack.push(1);
    stack.push(2);
    stack.pop();
    stack.pop();
    System.out.println("min is "+stack.getMin());
  }
}

執行結果,親測可用:

min is 3

二:由兩個棧組成的佇列
  題目:編寫一個類,用兩個棧實現佇列,支援棧的基本操作(add、poll、peek)
  思路:棧是先進後出,佇列是先進先出,所以剛好可以用兩個棧來實現這種資料結構
     但是在資料彈出和壓入到另一個棧的時候,需要注意兩個點,如果stackPush要往stackPop壓入資料,
     那麼必須保證一次把stackPush中的資料全部壓入stackPop。如果stackPop不為空,stackPush不允許向stackPop壓入資料

圖示:
在這裡插入圖片描述

程式碼:

class TwoStactQueue {
  public Stack<Integer> stackPush;
  public Stack<Integer> stackPop;

  public TwoStactQueue() {
    stackPop = new Stack<>();
    stackPush = new Stack<>();
  }

  public void add(int num) {
    stackPush.push(num);
  }

  public int poll() {
    if (stackPop.isEmpty() && stackPush.isEmpty()) {
      throw new RuntimeException("Queue is empty");
    } else if (stackPop.isEmpty()) {
      while (!stackPush.empty()) {
        stackPop.push(stackPush.pop());
      }
    }
    return stackPop.pop();
  }

  public int peek() {
    if (stackPop.isEmpty() && stackPush.isEmpty()) {
      throw new RuntimeException("Queue is empty");
    } else if (stackPop.isEmpty()) {
      while (!stackPush.empty()) {
        stackPop.push(stackPush.pop());
      }
    }
    return stackPop.peek();
  }
}

測試類:

public class StackToQueue {
  public static void main(String[] args) {
    TwoStactQueue queue = new TwoStactQueue();
    queue.add(1);
    queue.add(2);
    queue.add(3);
    System.out.println(queue.poll() + "," + queue.poll());
    queue.add(4);
    queue.add(5);
    System.out.println(queue.poll() + "," + queue.peek() + "," + queue.poll());
  }
}

執行結果,親測可用:

1,2
3,4,4

三:如何僅用遞迴函式和棧操作逆序一個棧
  題目:將一個棧中的內容逆序輸出,只用遞迴函式來實現
  思路:可以用兩個遞迴函式來實現
     第一個遞迴函式用來將棧底數字取出,第二個遞迴函式用來將數字入棧
  圖示:
  
在這裡插入圖片描述

程式碼:

public class ReverStack {
  public static void main(String[] args) {
    Stack<Integer> stack = new Stack<>();
    stack.push(3);
    stack.push(2);
    stack.push(1);
    reverse(stack);
    System.out.println(stack.toString());
  }

    /**
     * 將棧stack的棧底元素返回並移除
     *
     * @return 棧底元素
     */
  public static int getAndRemoveLastElement(Stack<Integer> stack){
      int result = stack.pop();
      if(stack.isEmpty()){
          return result;
      }else{
          int last = getAndRemoveLastElement(stack);
          stack.push(result);
          return last;
      }
  }

  public static void reverse(Stack<Integer> stack){
      if(stack.isEmpty()){
          return;
      }
      int i = getAndRemoveLastElement(stack);
      reverse(stack);
      stack.push(i);
  }
}

測試結果,親測可用:

[1, 2, 3]