数据结构栈和队列以及常见算法题
棧
概念:一種特殊的線性表,其只允許在固定的一端進行插入和刪除元素操作。進行數據插入和刪除操作的一端稱為棧頂,另一端稱為棧底。棧中的數據元素遵守后進先出LIFO(Last In First Out)的原則。
壓棧:棧的插入操作叫做進棧/壓棧/入棧,入數據在棧頂。
出棧:棧的刪除操作叫做出棧。出數據在棧頂。
數據結構的棧和jvm運行時內存區域中的stack是啥關系:
方法的調用涉及到棧幀,調用一個方法就壓棧,方法執行完就出棧。棧幀中有局部變量表,局部變量表存放的是方法調用過程中的局部變量。
操作:
import java.util.Deque; import java.util.LinkedList; import java.util.Stack;//如何實現棧 public class StackDemo {public static void main(String[] args) {//使用stack // Stack<String> stack = new Stack<>(); // // stack.push("A"); // stack.push("B"); // stack.push("C"); // // System.out.println(stack.size()); // 3 // System.out.println(stack.isEmpty()); // false // System.out.println(stack.empty()); // false // System.out.println(stack); // // System.out.println(stack.peek()); // C // System.out.println(stack.peek()); // C // System.out.println(stack.pop()); // C // System.out.println(stack.pop()); // B//使用DequeDeque<String> stack = new LinkedList<>();stack.push("A");stack.push("B");stack.push("C");System.out.println(stack);System.out.println(stack.isEmpty()); // falseSystem.out.println(stack.size()); // 3System.out.println(stack.peek()); // CSystem.out.println(stack.peek()); // CSystem.out.println(stack.pop()); // CSystem.out.println(stack.pop()); // B} }題目20:有效的括號
根據括號的匹配原則,選擇數據結構為棧。
創建一個空棧,存儲內容為字符,將字符串轉化為字符數組;
遍歷字符數組,如果是左括號就入棧,如果是右括號
- 如果棧為空,直接返回false
- 彈出棧頂元素看是否匹配,不匹配就直接返回false;匹配就繼續遍歷下一個字符
題目:劍指offer31棧的壓入,彈出序列
private List<Integer> arrayToList(int []array){List<Integer> list = new ArrayList<>(array.length);for (int e: array){list.add(e);}return list;}public boolean validateStackSequences(int[] pushed, int[] popped) {List<Integer> pushedList = arrayToList(pushed);List<Integer> popedList = arrayToList(popped);Stack<Integer> stack = new Stack<>();for (int e : pushedList){if (!stack.isEmpty() && stack.peek() == e){stack.pop();continue;}while (true) {if (pushedList.isEmpty()) {return false;}int f = pushedList.remove(0);if (f != e) {stack.push(f);} else {break;}}}return stack.isEmpty();}題目225:用兩個隊列實現棧
方法一:
push:
1.選擇一個隊列(哪個隊列中有數據選哪個,都沒有就指定一個)
2.把元素加入隊列中
pop:
1.選擇一個隊列(有數據的隊列)
2.把該隊列中的size - 1個數據移動到另一個隊列中
3.把隊列剩余的元素出掉
top:
1.選擇一個隊列(有數據的那個隊列)
2.把該隊列中的size-1個數據移動到另一個隊列中
3.把隊列剩余的返回,并且把該元素放入另一個隊列中
方法二:
還有一種方法不必使用到兩個隊列,使用一個隊列即可,先將所有元素入隊列,如果要取元素就把前size-1個個元素又放回隊列,將最后一個出隊列,依次這樣操作。
方法一的實現:
題目155:最小棧
本題要求的時間復雜度是O(1),push操作個peek操作原本就是O(1),獲取棧中的最小元素,要么是遍歷棧的元素得出最小元素,要么就是創建一個遍歷記錄,這里我們使用一個棧來進行記錄,這樣做的好處是利用了入棧和出棧O(1)的時間復雜度。
push :val入棧普通棧;最小棧:如果val<=最小棧的棧頂元素,那么該元素也入棧最小棧。
為什么這里是<=呢?很多人可能會疑問,如果等于此時最小棧的棧頂元素,那么最小值不是已經在最小棧中存在了嗎,為什么還要入棧?因為我們忽略了一種特殊情況:
pop:普通棧出棧x,如果x==最小棧的棧頂元素那么最小棧才出棧。
class MinStack {//正確private Stack<Integer> normal = new Stack<>();private Stack<Integer> min = new Stack<>();/** initialize your data structure here. */public MinStack() {}public void push(int val) {normal.push(val);if (min.isEmpty() || val <= min.peek()) {min.push(val);} else {min.push(min.peek());}}public void pop() {normal.pop();min.pop();}public int top() {return normal.peek();}public int getMin() {return min.peek();} }隊列
概念:只允許在一端進行插入數據操作,在另一端進行刪除數據操作的特殊線性表,具有先進先出的特點。
入隊列:進行插入操作的一端稱為隊尾(Tail/Rear)
出隊列:進行刪除操作的一端稱為隊頭(Head/Front)
尾插頭刪
操作:
題目232:用棧實現隊列
push:將數據放入棧2
pop:如果1號棧空了,把二號棧的所有元素放到一號棧,從棧1出數據
peek:如果棧1中有數據,直接從棧1中取數據,如果棧1沒有數據,棧2中有數據就去將棧2中的所有元素放入棧1再從棧1取數據
題目622:設計循環隊列
但是rear==front的時候無法判斷隊列是空還是滿。
為了達到判斷循環隊列滿的條件,犧牲一個空間。
取隊首元素:array[frontIndex]
取隊尾元素:array[(rearIndex - 1 + array.length) % array.length]
隊滿:(rearIndex+1)%array.length == frontIndex
隊空:rearIndex = = frontIndex
總結
以上是生活随笔為你收集整理的数据结构栈和队列以及常见算法题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 空调定时和睡眠的区别(如何选择空调)
- 下一篇: Servlet的快速入门以及执行原理