深入理解棧與隊列——從原理理解到實戰應用

目錄

一、引言

二、棧(Stack)

2.1 棧的基本概念

2.2 棧的使用

2.3 棧的模擬實現

2.4 棧的實戰應用

2.4.1 括號匹配

2.4.2 逆波蘭表達式求值

2.4.3 出棧入棧次序匹配

2.4.4 最小棧

三、隊列(Queue)

3.1 隊列的基本概念

3.2 隊列的使用

3.3 隊列的模擬實現

3.4 隊列的實戰應用

3.4.1 設計實現循環隊列

四、常見面試題與實戰應用

4.1 用隊列實現棧

4.2 用棧實現隊列

五、總結


一、引言

數據結構是編程的基石,無論是算法設計還是系統開發,都離不開對數據結構的深入理解。棧和隊列作為兩種最基礎的線性數據結構,廣泛應用于各種場景中。本文將系統性地介紹棧和隊列的概念、實現方式以及實際應用,幫助讀者建立完整的知識體系。

二、棧(Stack)

2.1 棧的基本概念

棧是一種遵循先進后出FILO,First In Last Out)原則的線性數據結構,只允許在棧頂進行入棧(壓棧)和出棧操作。

拿生活中的一些現象舉例子:比如超市里盤子售賣區的一摞一摞盤子,我們想要新增盤子只能放在最頂部,同樣地,拿出盤子也只能在最頂部拿。

2.2 棧的使用

在Java內置的Stack類中,提供了以下操作方法:

public void push(int data)入棧/壓棧,即增加新元素
public int pop()出棧,即刪除棧頂的元素并返回該元素
public int peek()獲取棧頂元素并返回,不刪除
public boolean empty()判斷棧是否為空
public int size()獲取棧的大小

具體使用示例如下:

import java.util.Stack;public class StackExample {public static void main(String[] args) {Stack<Integer> stack = new Stack<>();// 壓棧操作stack.push(1);stack.push(2);stack.push(3);// 查看棧頂元素System.out.println("棧頂元素: " + stack.peek()); // 輸出 3// 出棧操作System.out.println("出棧: " + stack.pop()); // 輸出 3System.out.println("出棧: " + stack.pop()); // 輸出 2// 判斷棧是否為空System.out.println("棧是否為空: " + stack.empty()); // 輸出 false// 獲取棧的大小System.out.println("棧的大小: " + stack.size());   // 輸出 1}
}

2.3 棧的模擬實現

在模擬實現棧時,我們可以選用數組也可以選用鏈表:用數組實現的棧叫順序棧;用鏈表實現的棧叫鏈式棧。

我們先編寫一個 MyStack 類如下:

public class MyStack {// 順序棧public int[] arr;public int usedSize;           //用于記錄棧的元素個數public MyStack(int[] arr) {this.arr = new int[10];    //暫定長度為10}// 鏈式棧(單向)static class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public int usedSize;           //用于記錄棧的元素個數// 鏈式棧(雙向)static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public ListNode tail;public int usedSize;           //用于記錄棧的元素個數
}

接下來我們來實現 push方法,思路很簡單,我們只需要在 usedSize 位置增加新元素就可以了,但是要注意棧滿了的時候,需要擴容。

順序棧實現如下:

public void push(int data) {if (empty()) {this.arr = Arrays.copyOf(this.arr,2*this.arr.length);    //擴容為原長度的2倍}arr[usedSize] = data;usedSize++;
}

單向鏈式棧實現思路:使用頭插法入棧,時間復雜度是O(1)

public void push(int data) {// 頭插法入棧ListNode toAdd = new ListNode(data);toAdd.next = head;head = toAdd;usedSize++;
}

雙向鏈式棧實現方式可以頭插也可以尾插。

public void push(int data) {// 頭插法ListNode toAdd = new ListNode(data);toAdd.next = head;head.prev = toAdd;head = head.prev;usedSize++;
}public void push(int data) {// 尾插法ListNode toAdd = new ListNode(data);tail.next = toAdd;toAdd.prev = tail;tail = tail.next;usedSize++;
}

然后是 pop方法,我們只需要將?usedSize 的個數減一即可。雖然元素在數組中仍然存在,但是不需要擔心,等到下次增加元素時,該元素將被覆蓋。

順序棧實現如下:

public int pop() {if (empty()) {throw new EmptyStackException("This stack is empty!");}usedSize--;return this.arr[usedSize];
}

單向鏈式棧:我們可以使用頭刪法,每次刪除并返回鏈表的第一個節點

public int pop() {if (empty()) {throw new EmptyStackException("This stack is empty!");}int val = head.val;head = head.next;usedSize--;return val;
}

雙向鏈式棧:與單向鏈式棧不同的是,我們需要把第二個節點的 prev 置空

public int pop() {if (empty()) {throw new EmptyStackException("This stack is empty!");}int val = head.val;head = head.next;head.prev = null;usedSize--;return val;
}

其中的異常編寫如下:

public class StackEmptyException extends RuntimeException {public StackEmptyException() {super();}public StackEmptyException(String message) {super(message);}
}

peek方法十分簡單,只需要返回 usedSize - 1 位置的元素即可,但是注意要判斷棧是否為空。

順序棧實現如下:

public int peek() {if (empty()) {throw new EmptyStackException("This stack is empty!");}return this.arr[usedSize-1];
}

單/雙向鏈式棧:直接返回鏈表第一個節點的 val 即可

public int peek() {if (empty()) {throw new EmptyStackException("This stack is empty!");}return head.val;
}

empty方法,只需判斷 usedSize 是否等于數組的長度即可。

順序棧實現如下:

public boolean empty() {return usedSize == this.arr.length;
}

單/雙向鏈式棧:判斷指向鏈表第一個節點的引用是否為空即可

public boolean empty() {if (head == null) return true;return false;
}

最簡單的是 size方法,只需要返回 usedSize 即可:

public int size() {return this.usedSize;
}

對于單/雙鏈式棧來說,需要遍歷整個棧:

public int size() {ListNode cur = head;int count = 0;while (cur != null) {count++;cur = cur.next;}return count;
}

2.4 棧的實戰應用

棧相關的面試題:

2.4.1 括號匹配

算法實現思路:

  1. 遍歷字符串,如果是左括號,就放入棧中;如果是右括號,就獲取棧頂元素并進行匹配
  2. 情況一:當棧為空并且字符串遍歷完成,左右括號都匹配成功時,返回true;情況二:當左右括號匹配失敗時,返回false;情況三:當字符串遍歷完成但是棧不為空時,表示左括號多余,返回false;情況四:當字符串未遍歷完成但是棧已經空了,表示右括號多余,返回false。
  3. 注意:當遍歷字符串發現字符是右括號時,在匹配前必須先檢查棧是否為空:若不為空才進行匹配;若為空則是第四種情況

具體實現如下:

public boolean isValid(String s) {Stack<Character> stack = new Stack<>();for (int i = 0; i < s.length(); i++) {char ch = s.charAt(i);if (ch=='(' || ch=='[' || ch=='{') {stack.push(ch);} else {    // 此時 ch 是右括號if (stack.empty()) {       // 棧已空,右括號多余return false;}char leftCh = stack.peek();if ((leftCh=='(' && ch==')')|| (leftCh=='[' && ch==']')|| (leftCh=='{' && ch=='}')) {     // 匹配成功stack.pop();} else {               // 匹配失敗return false;}}}if (!stack.empty()) {       // 棧不為空但字符串已經遍歷完成,左括號多余return false;}return true;
}

2.4.2 逆波蘭表達式求值

算法實現思路:

  1. 遍歷,遇到數字就放入棧,遇到運算符就取出兩個棧頂數字并進行計算(第一個取出的數字作為右操作數,第二個作為左操作數),將計算結果放入棧
  2. 當遍歷完成后,棧中所存的元素就是該表達式的最終結果

中綴表達式轉后綴表達式(逆波蘭表達式)的計算方法:

  1. 先判斷中綴表達式的優先級,然后按照優先級依次在算式外部添加括號
  2. 全部添加完成后,從左至右依次將運算符移至括號后面
  3. 例:中綴表達式 a + b * c + ( d * e + f ) * g?
  4. 首先劃分優先級:
  5. 單項式( d * e ) ——> 多項式( ( d * e ) + f ) ——> 多項式( ( d * e ) + f ) * g ) ——> 單項式( b * c )?——> 多項式( a + ( b * c ) ) ——> 多項式( ( a + ( b * c ) ) + ( ( d * e ) + f ) * g ) )
  6. 然后按照優先級先后把運算符全部移到括號后面:
  7. ( ( a + ( b * c ) ) + ( ( ( d * e ) + f ) * g ) ) ——> (?( a ( b c ) * ) + ( ( ( d e ) * f ) + g ) * ) +
  8. 去掉所有的括號最終結果就是:
  9. ?a b c * + d e * f + g * +

具體實現如下:

public int evalRPN(String[] tokens) {Stack<Integer> stack = new Stack<>();for (String s : tokens) {if (s.equals("+")|| s.equals("-")|| s.equals("*")|| s.equals("/")) {    // 是運算符int v2 = stack.pop();   // 右操作符int v1 = stack.pop();   // 左操作符switch (s) {case "+":stack.push(v1+v2);break;case "-":stack.push(v1-v2);break;case "*":stack.push(v1*v2);break;case "/":stack.push(v1/v2);break;}} else {            // 是數字int val = Integer.parseInt(s);  // 轉換為整型stack.push(val);}}return stack.pop();
}

2.4.3 出棧入棧次序匹配

算法實現思路:

  1. 遍歷pushV數組并入棧,每次入棧一個元素之后拿棧頂元素與popV數組中的 j 位置的元素進行比較是否相等:若一樣,就可以出棧;否則,繼續遍歷pushV數組、入棧
  2. 一旦有一個元素相等,后面的所有元素均相等
  3. 當棧為空或者popV數組和pushV數組遍歷完成時,返回true

具體實現如下:

public boolean isPopOrder (int[] pushV, int[] popV) {Stack<Integer> stack = new Stack<>();int j = 0;for (int i = 0; i < pushV.length; i++) {stack.push(pushV[i]);while (j < popV.length&& !stack.isEmpty()&& stack.peek() == popV[j]) {stack.pop();j++;}}return stack.isEmpty();
}

2.4.4 最小棧

算法實現思路:

  1. 使用兩個棧,一個普通棧(stack)存放所有的數據,一個最小棧(minStack)用于存放當前 stack 所存元素的最小值
  2. 入棧:當第一個元素放入 stack ,且 minStack 為空時,minStack 也要放。接下來 stack 存放元素后,都要與 minStack 的棧頂元素進行大小比較:若比棧頂元素小,就放入 minStack(注意:若與棧頂元素相等,也要放入);否則不放入
  3. 出棧:當普通棧出一個元素時,判斷一下最小棧是否也有相同的元素:若有就出;否則不出

具體實現如下:

public class MinStack {Stack<Integer> stack;Stack<Integer> minStack;public MinStack() {stack = new Stack<>();minStack = new Stack<>();}public void push(int val) {stack.push(val);if (minStack.empty()) {minStack.push(val);} else {if (val <= minStack.peek()) {minStack.push(val);}}}public void pop() {if (stack.empty()) return;int val = stack.pop();if (minStack.peek() == val) {minStack.pop();}}public int top() {if (stack.empty()) return -1;return stack.peek();}public int getMin() {if (stack.empty()) return -1;return minStack.peek();}
}

三、隊列(Queue)

3.1 隊列的基本概念

隊列是一種遵循先進先出FIFO, First In First Out)原則的線性數據結構。只允許在隊尾進行插入操作,在隊頭進行刪除操作。

現實生活中的隊列例子:

  • 排隊購票:先來的人先得到服務
  • 打印機任務隊列:先提交的打印任務先執行

3.2 隊列的使用

在Java內置的Queue類中,提供了以下操作方法:

public void offer(int data)入隊,即增加新元素
public int poll()出隊,即刪除隊頭元素并返回該元素
public int peek()獲取隊頭元素并返回,不刪除
public boolean isEmpty()判斷隊列是否為空
public int size()獲取隊列的大小

具體使用示例如下:

import java.util.LinkedList;
import java.util.Queue;public class QueueExample {public static void main(String[] args) {Queue<Integer> queue = new LinkedList<>();// 入隊操作queue.offer(1);queue.offer(2);queue.offer(3);// 查看隊頭元素System.out.println("隊頭元素: " + queue.peek()); // 輸出 1// 出隊操作System.out.println("出隊: " + queue.poll()); // 輸出 1System.out.println("出隊: " + queue.poll()); // 輸出 2// 判斷隊列是否為空System.out.println("隊列是否為空: " + queue.isEmpty()); // 輸出 false// 獲取隊列的元素個數System.out.println("隊列的長度: " + queue.size()); // 輸出 1}
}

3.3 隊列的模擬實現

由于Java的內置隊列 Queue 是采用雙向鏈表實現的,我們這里也使用雙向鏈表。各個方法的實現思路與棧的方法的實現思路差不多,此處不再過多闡述。

具體實現如下:

public class MyQueue {static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode first;public ListNode last;public int usedSize;public void offer(int data) {   // 尾插ListNode toAdd = new ListNode(data);if(first == null) {first = last = toAdd;return;}last.next = toAdd;toAdd.prev = last;last = last.next;usedSize++;}public int poll() {    // 頭刪if(first == null) {return -1;}int v = first.val;first = first.next;if (first != null) {first.prev = null;}usedSize--;return v;}public int peek() {     // 獲取隊頭的值if(first == null) {return -1;}return first.val;}public int size() {    // 獲取隊列的大小return usedSize;}
}

3.4 隊列的實戰應用

3.4.1 設計實現循環隊列

我們把一個數組卷起來呈圓形,以這樣的結構來實現的隊列稱為循環隊列。

當兩個引用 front? 和 rear 指向同一個位置(即 front == rear)時,該隊列為空。

它的方法如下:

public boolean enQueue(int value)入隊,即增加新元素
public boolean deQueue()出隊,即刪除隊頭元素并返回該元素
public int Front()獲取隊頭元素并返回
public int Rear()獲取隊尾元素并返回
public boolean isEmpty()判斷隊列是否為空
public boolean isFull()判斷隊列空間是否已滿

算法實現思路:

  1. 如何判斷隊列為空/隊列已滿?:當 front == rear
  2. 怎么區分為空還是為滿?:1.定義 usedSize;2.空出最后一個位置;3.添加一個布爾類型的變量作為標記
  3. 怎么做到循環遍歷隊列?即怎么讓 rear 從下標為7的位置走到下標為0的位置呢?:用公式( rear + 1 ) % array.length判斷 rear 的下一個是否 front
  4. 入隊列、出隊列、返回隊頭元素、返回隊尾元素(需要判斷 rear)

具體實現如下:

class MyCircularQueue {    // 這里采用的是第二種方法區分為空還是為滿public int front;public int rear;public int[] elem;public MyCircularQueue(int k) {this.elem = new int[k+1];}public boolean enQueue(int value) {    // 入隊列if (isFull()) {return false;}elem[rear] = value;rear = (rear+1)%elem.length;return true;}public boolean deQueue() {    // 出隊列if (isEmpty()) {return false;}front = (front+1)%elem.length;return true;}public int Front() {    // 獲取隊頭元素if (isEmpty()) {return -1;}return elem[front];}public int Rear() {    // 獲取隊尾元素if (isEmpty()) {return -1;}int pos = (rear==0) ? elem.length-1 : rear-1;return elem[pos];}public boolean isEmpty() {return rear == front;}public boolean isFull() {return (rear+1)%elem.length == front;}
}

四、常見面試題與實戰應用

4.1 用隊列實現棧

算法實現思路(使用兩個隊列):

  1. 模擬的入棧操作:將入棧的元素放入不為空的隊列中;
  2. 第一次入棧默認放入qu1中,接下來判斷哪個隊列不為空就放入哪個隊列中:if...else if...else
  3. 模擬的出棧操作:把不為空的隊列中的除要出棧的元素之外的(size-1)所有元素放入另一個隊列當中,再出隊列即可;先判斷棧是否為空,再判斷哪個隊列不為空就出哪個隊列
  4. 模擬的獲取棧頂元素操作:在出棧操作的基礎下(把全部元素都出),加一個變量存儲出隊列的元素,當最后一個出隊列的元素存儲后,該值就是模擬的棧頂元素
  5. 兩個隊列交替工作

具體實現如下:

public class MyStack {Queue<Integer> qu1;Queue<Integer> qu2;public MyStack() {qu1 = new LinkedList<>();qu2 = new LinkedList<>();}public void push(int x) {if (!qu1.isEmpty()) {qu1.offer(x);} else if (!qu2.isEmpty()) {qu2.offer(x);} else {qu1.offer(x);}}public int pop() {if (empty()) {return -1;}if (!qu1.isEmpty()) {int size = qu1.size();for (int i = 0; i < size-1; i++) {qu2.offer(qu1.poll());}return qu1.poll();} else {int size = qu2.size();for (int i = 0; i < size-1; i++) {qu1.offer(qu2.poll());}return qu2.poll();}}public int top() {if (empty()) {return -1;}if (!qu1.isEmpty()) {int size = qu1.size();int val = 0;for (int i = 0; i < size; i++) {val = qu1.poll();qu2.offer(val);}return val;} else {int size = qu2.size();int val = 0;for (int i = 0; i < size; i++) {val = qu2.poll();qu1.offer(val);}return val;}}public boolean empty() {return qu1.isEmpty() && qu2.isEmpty();}
}

4.2 用棧實現隊列

算法實現思路(使用兩個棧):

  1. 指定一個棧用來入隊列,一個棧用來出隊列
  2. 模擬的入隊列操作:放入指定的入隊列棧中即可
  3. 模擬的出隊列操作:先判斷出隊列棧是否為空?:若為空,將入隊列棧中的元素放入出隊列棧中,再出棧即可;否則直接出棧
  4. 模擬的獲取隊頭元素操作:在出隊列操作下,直接peek出隊列棧的棧頂元素即可

具體實現如下:

public class MyQueue {Stack<Integer> st1;Stack<Integer> st2;public MyQueue() {st1 = new Stack<>();st2 = new Stack<>();}public void push(int x) {st1.push(x);}public int pop() {if (empty()) {return -1;}if (st2.isEmpty()) {while (!st1.isEmpty()) {st2.push(st1.pop());}}return st2.pop();}public int peek() {if (empty()) {return -1;}if (st2.isEmpty()) {while (!st1.isEmpty()) {st2.push(st1.pop());}}return st2.peek();}public boolean empty() {return st1.isEmpty() && st2.isEmpty();}
}

五、總結

棧和隊列是編程中最基礎且重要的數據結構,理解它們的特性和應用場景對每個程序員都至關重要:

  1. 遵循FILO原則,適合用于需要"回溯"的場景,如函數調用、括號匹配、深度優先搜索等

  2. 隊列遵循FIFO原則,適合用于需要"排隊"的場景,如廣度優先搜索、消息隊列、任務調度等

  3. 雙端隊列結合了棧和隊列的特性,提供了更靈活的操作方式

  4. 在實際開發中,應根據具體需求選擇合適的數據結構,或者組合使用多種數據結構解決問題

掌握這些基礎數據結構不僅有助于解決算法問題,也能為理解更復雜的系統設計打下堅實基礎。

相信讀者朋友看到這里已經能夠掌握棧和隊列的基本操作了 ~


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/97707.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/97707.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/97707.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用html5寫王者榮耀之王者墳墓的游戲2deepseek版

我將為您創建一個王者榮耀英雄墳墓游戲的提詞器HTML頁面。這個工具將幫助游戲主播或玩家在游戲中快速查看英雄技能、連招順序等信息。設計思路 創建英雄選擇界面實現提詞器顯示區域&#xff0c;可自定義文本內容添加字體大小、滾動速度控制設計符合王者榮耀風格的UI下面是…

輕閱讀:一鍵解決瀏覽器無法預覽Office文檔的實用方案

在日常辦公中&#xff0c;通過瀏覽器直接打開Word、Excel或PPT等文檔時&#xff0c;常遇到“需下載后用本地軟件打開”的困擾&#xff0c;不僅流程繁瑣&#xff0c;還面臨格式兼容、設備存儲不足等問題。輕閱讀&#xff08;QingYueDu&#xff09;作為一款輕量級文件在線預覽工具…

鴻蒙開發實戰項目(六十七):常見組件和容器低代碼開發示例(ArkTS)

本文詳細代碼需訂閱下面專欄獲取(訂閱后私信郵箱+項目名): https://blog.csdn.net/m0_68036862/category_12333038.html 目錄 介紹 環境搭建 代碼結構解讀 創建低代碼工程 低代碼設計界面布局 實現數據動態渲染 手動創建低代碼頁面 介紹 本篇Codelab是基于ArkTS語言的…

MySQL學習筆記04-DML-數據的增刪改

新增數據--insert樣例代碼-- DML : 數據操作語言 -- DML : 插入數據 - insert -- 1. 為 emp 表的 username, password, name, gender, phone 字段插入值 insert into emp (username,password,name,gender,phone) values(fei,123456,張飛,1,13888888888);-- 2. 為 emp 表的 所有…

拼多多返利app的服務網格(Service Mesh)實踐:Istio在導購系統中的應用

拼多多返利app的服務網格&#xff08;Service Mesh&#xff09;實踐&#xff1a;Istio在導購系統中的應用 大家好&#xff0c;我是阿可&#xff0c;微賺淘客系統及省賺客APP創始人&#xff0c;是個冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 在拼多多返利app的…

【RabbitMQ】高級特性:持久性·發送方確認·重試機制·TTL·死信隊列·延遲隊列·事務·消息分發

RabbitMQ的高級特性還包括我的上篇博客 【RabbitMQ】-----詳解RabbitMQ高級特性之消息確認機制-CSDN博客 目錄 RabbitMQ高級特性之持久性 持久性 交換機持久化 隊列持久化消息持久化 RabbitMQ高級特性之發送方確認機制 發送方確認 添加配置 常量類 聲明隊列和交換機…

鴻蒙Next ArkWeb網頁多媒體開發實戰:從基礎到高級應用

解鎖鴻蒙ArkWeb的強大多媒體能力&#xff0c;讓網頁視頻音頻體驗媲美原生應用在日常應用開發中&#xff0c;我們經常需要在應用中嵌入網頁并展示其中的多媒體內容。鴻蒙HarmonyOS Next的ArkWeb組件提供了強大的網頁渲染能力&#xff0c;尤其對網頁中的多媒體元素有出色的支持。…

06. Linux進程概念 1

Linux進程概念 馮諾依曼體系 馮諾依曼體系結構&#xff08;Von Neumann Architecture&#xff09;是現代計算機設計的奠基石&#xff0c;由數學家約翰馮諾依曼于1945年提出。這一架構徹底改變了早期計算機“硬件即程序”的設計方式&#xff0c;使得計算機可以靈活地運行不同程序…

HTTP標頭全解析:保護你的Web應用!

在網絡攻擊頻發的時代&#xff0c;你的Web應用是否像一座沒有城墻的城堡&#xff0c;任由XSS、點擊劫持和中間人攻擊入侵&#xff1f;HTTP標頭&#xff0c;這些看似不起眼的響應頭&#xff0c;其實是Web安全的隱形守護者。想象一個電商網站&#xff0c;用戶數據被竊取&#xff…

rt-linux下__slab_alloc里的另外一處可能睡眠的邏輯

一、背景 在之前的博客 tasklet上下文內存分配觸發might_alloc檢查及同步回收調用鏈 里&#xff0c;我們講了一處內存分配時會引起睡眠的調用鏈&#xff08;這個引起睡眠的這個調用鏈它是在普通linux里也是存在的&#xff09;。這篇博客里&#xff0c;我們講一處內存分配路徑下…

基于STM32F103C8T6的智能環境監測系統:DHT11溫濕度檢測與OLED顯示實現

引言 你是否曾想實時握身邊環境的溫濕度變化&#xff1f;無論是居家種植需要精準調控環境&#xff0c;還是實驗室存放敏感材料需監控條件&#xff0c;亦或是智能座艙場景下的環境感知&#xff0c;智能環境監測系統正成為連接物理世界與數字管理的重要橋梁。而在眾多嵌入式開發…

動態規劃在子數組/子串問題

目錄 一、最大子數組和&#xff08;LeetCode 53&#xff09; 二、環形子數組的最大和&#xff08;LeetCode 918&#xff09; 三、乘積最大子數組&#xff08;LeetCode 152&#xff09; 四、乘積為正數的最長子數組長度&#xff08;LeetCode 1567&#xff09; 五、等差數列…

微信小程序開發筆記(01_小程序基礎與配置文件)

ZZHow(ZZHow1024) 參考課程: 【尚硅谷微信小程序開發教程】 [https://www.bilibili.com/video/BV1LF4m1E7kB] 009_文件和目錄結構介紹新建頁面與調試基礎庫 一個完整的小程序項目分為兩個部分&#xff1a;主體文件、頁面文件 主體文件又稱全局文件&#xff0c;能夠作用于整…

NLP Subword 之 BPE(Byte Pair Encoding) 算法原理

本文將介紹以下內容&#xff1a; 1. BPE 算法核心原理2. BPE 算法流程3. BPE 算法源碼實現DemoBPE最早是一種數據壓縮算法&#xff0c;由Sennrich等人于2015年引入到NLP領域并很快得到推廣。該算法簡單有效&#xff0c;因而目前它是最流行的方法。GPT-2和RoBERTa使用的Subword算…

CSS 偽類選擇器

偽類選擇器&#xff08;pseudo-class selector&#xff09;是一種用于選擇HTML元素特定狀態或特征的關鍵字&#xff0c;它允許開發者基于文檔樹之外的信息&#xff08;如用戶交互、元素位置或狀態變化&#xff09;來選擇元素并應用樣式。偽類選擇器以冒號(:)開頭&#xff0c;附…

Electron 新特性:2025 版本更新解讀

引言&#xff1a;Electron 新特性在 2025 版本更新中的解讀核心價值與必要性 在 Electron 框架的持續演進中&#xff0c;新特性的引入是推動桌面開發創新的核心動力&#xff0c;特別是 2025 年的版本更新&#xff0c;更是 Electron 項目從成熟生態到前沿技術的躍進之鑰。它不僅…

MyBatis從入門到面試:掌握持久層框架的精髓

MyBatis從入門到面試&#xff1a;掌握持久層框架的精髓 前言 在Java企業級應用開發中&#xff0c;持久層框架的選擇至關重要。MyBatis作為一款優秀的半自動化ORM框架&#xff0c;以其靈活的SQL定制能力和良好的性能表現&#xff0c;成為了眾多開發者的首選。本文將帶你從MyBa…

5.Three.js 學習(基礎+實踐)

Three.js 是 “WebGL 的封裝庫”&#xff0c;幫你屏蔽了底層的著色器 / 緩沖區細節&#xff0c;專注于 “3D 場景搭建”&#xff0c;開發效率高&#xff0c;是通用 3D 開發的首選。他的核心是 “場景 - 相機 - 渲染器” 的聯動邏輯&#xff0c;先掌握基礎組件&#xff0c;再學進…

消火栓設備工程量計算 -【圖形識別】秒計量

消火栓設備工程量計算 -【圖形識別】秒計量 消防系統的消火栓設備水槍、水帶和消火栓組成&#xff0c;根據清單定額規則計算消火栓設備工程量。通過CAD快速看圖的圖形識別框選圖紙就能自動數出消火栓數量&#xff0c;省時又準確&#xff0c;是工程人做消防算量的好幫手。 一、…

Docker 與 VSCode 遠程容器連接問題深度排查與解決指南

Docker 與 VSCode 遠程容器連接問題深度排查與解決指南 引言 Visual Studio Code 的 Remote - Containers 擴展極大地提升了開發體驗&#xff0c;它將開發環境容器化&#xff0c;保證了環境的一致性&#xff0c;并允許開發者像在本地一樣在容器內進行編碼、調試和運行。然而&…