Leetcode 15 java

今天復習一下翻轉二叉樹

226. 翻轉二叉樹

給你一棵二叉樹的根節點?root?,翻轉這棵二叉樹,并返回其根節點。

示例 1:

輸入:root = [4,2,7,1,3,6,9]
輸出:[4,7,2,9,6,3,1]

示例 2:

輸入:root = [2,1,3]
輸出:[2,3,1]

示例 3:

輸入:root = []
輸出:[]

提示:

  • 樹中節點數目范圍在?[0, 100]?內
  • -100 <= Node.val <= 100

1 我的想法以及分析

翻轉以后的二叉樹對于每一個子節點來說就是左右互換了。

但是我不知道具體要怎么實現這個,而且返回的root是有順序的,不知道怎么弄啊。

借鑒了一下題解,要用遞歸,那么。。算了一點看不懂,找一下以前寫的博客。

好難啊不知道這個遞歸什么鬼,也沒有個while for循環的,結束條件在哪里?也沒把判斷null放里頭啊。

我是豬。

2 解析

別慌!遞歸看起來 “沒有循環”,其實是把循環的邏輯交給了函數自身調用,咱們一步步拆解,保證能懂。

一、核心思路:為什么是 “左右互換”?

翻轉二叉樹的本質,是對每一個節點,交換它的左子樹和右子樹

  • 比如示例 1 中的根節點4,要交換它的左子樹(以2為根)和右子樹(以7為根);
  • 接著處理2這個節點,交換它的左子樹(1)和右子樹(3);
  • 再處理7這個節點,交換它的左子樹(6)和右子樹(9);
  • 直到遇到 “空節點”(沒有子樹可交換),就停止。

二、遞歸怎么寫?3 步理清邏輯

遞歸的核心是 “明確函數做什么、終止條件是什么、子問題怎么拆”,咱們對應到這道題:

1. 明確函數功能

定義函數invertTree(root)

  • 輸入:一個節點root(可能是根,也可能是子樹的根);
  • 輸出:翻轉該節點所在子樹后,新的根節點(其實就是原root,因為只是交換子樹,根不變)。
2. 終止條件(“什么時候停”)

rootnull時(比如葉子節點的左 / 右子樹,或者空樹),沒有子樹可交換,直接返回null即可。
這就是遞歸的 “出口”,避免無限調用。

3. 子問題拆解(“當前節點要做什么”)

對一個非空節點root,只需要 3 步:

  1. 暫存左子樹:因為交換后會覆蓋左子樹,先把root.left存起來(比如叫leftTemp);
  2. 交換左右子樹
    • root的左子樹,改成 “翻轉后的右子樹”(即調用invertTree(root.right));
    • root的右子樹,改成 “翻轉后的左子樹”(即調用invertTree(leftTemp));
  3. 返回當前節點root(它的子樹已經翻轉完成)。

三、代碼實現(Java 示例)

java

運行

// 二叉樹節點定義
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val = val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}class Solution {public TreeNode invertTree(TreeNode root) {// 終止條件:遇到空節點,直接返回nullif (root == null) {return null;}// 1. 暫存左子樹(避免交換時被覆蓋)TreeNode leftTemp = root.left;// 2. 交換:左子樹 = 翻轉后的右子樹,右子樹 = 翻轉后的左子樹root.left = invertTree(root.right);root.right = invertTree(leftTemp);// 3. 返回當前節點(子樹已翻轉)return root;}
}

四、用示例 1 驗證流程(幫你 “看見” 遞歸)

輸入:root = [4,2,7,1,3,6,9](結構如下)

plaintext

    4/ \2   7/ \ / \
1  3 6  9

遞歸執行步驟(簡化):

  1. 處理4:暫存左子樹2,調用invertTree(7)(先翻轉右子樹)、invertTree(2)(再翻轉左子樹);
  2. 處理7:暫存左子樹6,調用invertTree(9)(返回9)、invertTree(6)(返回6),交換后7的左 = 9、右 = 6;
  3. 處理2:暫存左子樹1,調用invertTree(3)(返回3)、invertTree(1)(返回1),交換后2的左 = 3、右 = 1;
  4. 回到4:交換后4的左 = 7(已翻轉)、右 = 2(已翻轉),最終返回4

最終結果就是[4,7,2,9,6,3,1],和示例一致。

五、關鍵誤區糾正!!!!!!!!!!!

  • 不是 “沒有循環”:遞歸的 “循環” 是通過函數調用實現的,每個節點都會被處理一次,終止條件if (root == null)就是 “循環停止” 的信號;
  • 不用糾結 “返回順序”:遞歸會自動處理所有子節點,我們只需要關注 “當前節點要交換左右子樹”,剩下的交給子調用即可。

多拿幾個簡單例子(比如示例 2)走一遍流程,很快就能理解遞歸的 “自下而上” 處理邏輯啦!

3 自己重新理一遍

題目已給代碼

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public TreeNode invertTree(TreeNode root) {}
}

if (root == null){

return null;

}

TreeNode left = invertTree(root.left);

//【我感覺有點像套娃?】

插播一條。

“套娃” 這個比喻特別精準!遞歸的核心邏輯其實就是 “套娃”,咱們可以順著這個比喻再拆解一層,幫你徹底打通思路:

一、遞歸 = “拆解套娃” + “組裝套娃”

翻轉二叉樹的遞歸過程,完全可以對應成處理一套嵌套的玩具:

  1. 目標:把一套 “二叉樹套娃” 的每一層左右反過來(比如大娃里的中娃左右互換,中娃里的小娃也左右互換);
  2. 處理方式
    • 拿到一個娃(比如根節點4),先不管它本身,先把它左手里的小套娃(左子樹2)和右手里的小套娃(右子樹7)拆下來;
    • 分別把這兩個小套娃各自翻好(遞歸調用invertTree(2)invertTree(7),相當于把小套娃的內部全翻完);
    • 再把翻好的兩個小套娃 “左右對調”,塞回大娃的手里;
  3. 終止:拆到最后發現是個 “空殼”(root == null),沒有小套娃可拆,直接停下來。

二、用 “套娃” 看示例 1 的執行

原套娃結構(從外到內):4(外層)→ 左手2、右手7?→?2的左手1、右手37的左手6、右手9

  1. 先拆4的右手7(先處理右子樹):

    • 7的右手99沒有小套娃(左右都是null),翻完還是9,塞回7左手
    • 7的左手66沒有小套娃,翻完還是6,塞回7右手
    • 現在7的左右反過來了(左手9、右手6),整體塞回4左手
  2. 再拆4原來的左手2

    • 2的右手3:翻完還是3,塞回2左手
    • 2的左手1:翻完還是1,塞回2右手
    • 現在2的左右反過來了(左手3、右手1),整體塞回4右手
  3. 最后4的左右(72)都翻好了,整個套娃就翻完了。

三、為什么 “套娃” 能 work?

因為翻轉二叉樹的每一層邏輯都完全相同—— 不管是外層的4,還是中間的2/7,甚至最內層的1/3,要做的事都是 “拆左右小套娃→翻小套娃→對調塞回去”。

遞歸之所以不用for/while,就是因為它把 “一層一層拆套娃” 的重復工作,交給了函數自己調用自己,而if (root == null)就是 “拆到最里面空殼” 的停止信號。

你能想到 “套娃” 這個比喻,其實已經抓住了遞歸的核心 ——重復處理相似的子問題,直到沒有子問題可處理,接下來只要多走幾遍簡單案例,就能從 “感覺像” 變成 “完全懂” 啦!

TreeNode left = invertTree(root.left);

TreeNode right = invertTree (root.right);

root.left = right; root.right = left;

//這一段代碼是按順序執行的話,那么后面的root.left經一次調用的時候,第二次是不是這個root已經變了?

這個問題問到了遞歸執行順序的關鍵 ——代碼會先完整執行完前兩行的遞歸調用,再執行后面的賦值操作,所以不存在 “后面調用時 root 已經變了” 的情況。咱們一步步拆解:

一、核心結論

這三行代碼的執行順序是 “先算完左右子樹的翻轉結果,再給當前 root 的左右賦值”,前兩行的遞歸調用不會受后兩行賦值的影響。

二、用 “執行步驟拆解” 看為什么

咱們把代碼拆成 “計算結果” 和 “修改當前節點” 兩個階段,對應到具體執行:

階段 1:計算 “翻轉后的左右子樹”(前兩行代碼)

java

運行

// 1. 先計算“翻轉后的左子樹”:調用invertTree處理root原本的left
TreeNode left = invertTree(root.left);  
// 2. 再計算“翻轉后的右子樹”:調用invertTree處理root原本的right
TreeNode right = invertTree(root.right);  
  • 這兩步的核心是 “獲取結果”:不管遞歸調用多深,都會先把root原本的左子樹翻轉完,把結果存在left變量里;再把root原本的右子樹翻轉完,把結果存在right變量里。
  • 此時,root本身的leftright還沒被修改(還是原來的樣子),因為第三、四行的賦值代碼還沒執行。
階段 2:修改當前 root 的左右子樹(后兩行代碼)

java

運行

// 3. 用之前算好的“翻轉后的右子樹”,覆蓋當前root的left
root.left = right;  
// 4. 用之前算好的“翻轉后的左子樹”,覆蓋當前root的right
root.right = left;  
  • 這兩步才是 “修改當前節點”,而且用的是階段 1 已經算好的固定結果leftright變量),和后續遞歸無關。

三、用 “套娃” 比喻再驗證

假設當前處理的是根節點4(原左 = 2,原右 = 7):

  1. 執行TreeNode left = invertTree(4.left):其實就是去翻 “2這個套娃”,翻完后把結果(翻好的2,左 = 3、右 = 1)存在left里;
  2. 執行TreeNode right = invertTree(4.right):去翻 “7這個套娃”,翻完后把結果(翻好的7,左 = 9、右 = 6)存在right里;
  3. 這時候才執行4.left = right(把翻好的7塞給4的左)、4.right = left(把翻好的2塞給4的右)。

整個過程中,翻2和翻7的時候,4的左右還是原來的27,完全沒被修改 —— 因為賦值操作是最后才做的。

四、關鍵誤區澄清

你擔心的 “第二次調用時 root 已經變了”,本質是誤以為 “執行第二行invertTree(root.right)時,第一行已經修改了 root”。但實際是:

  • 前兩行都是 “讀取并處理 root 原本的左右子樹”,不修改 root;
  • 只有等前兩行的遞歸全執行完,才會修改 root 的左右。

所以遞歸過程中,每個節點的 “原始左右子樹” 都是固定的,不會被提前修改,放心就好~

【我的意思是第一次交換過了左右節點,第二次回頭再來一遍這里的root就變了?】

你的疑問核心是 “會不會有第二次回頭處理同一個 root”—— 答案是不會!遞歸的邏輯是 “處理一個節點時,只處理一次,且處理完就不再回頭”,每個節點的 “左右交換” 只執行 1 次,不存在 “第二次再來一遍” 的情況。咱們從 “遞歸的調用鏈路” 和 “節點處理次數” 兩個角度說透:

一、遞歸是 “向下拆解,向上組裝”,每個節點只被 “處理一次”

遞歸處理二叉樹的過程,像 “從根節點往下拆套娃,拆到最內層后,再從內往外組裝”——每個節點只會在 “組裝到它” 的時候,執行一次交換邏輯,之后再也不會被這個遞歸流程重新處理。

用示例 1 的根節點4舉例,完整鏈路是:

  1. 向下拆:處理4時,先去拆它的左子樹2?→ 拆2時,再去拆它的左子樹1?→?1沒有子節點(拆到最內層),直接返回1
  2. 向上裝:回到2,處理2的右子樹3(拆完返回3)→ 此時2的左右子樹都拆完,執行2的交換(左 = 3,右 = 1)→?2處理完,返回給4
  3. 再處理4的右子樹7(同樣 “拆→裝”,交換后返回7);
  4. 最后回到4,執行4的交換(左 = 7,右 = 2)→?4處理完,整個流程結束。

整個過程中,4271369每個節點都只被 “處理一次”(只執行一次自己的 “交換左右” 邏輯),處理完就作為結果返回給父節點,不會有 “第二次回頭處理同一個節點” 的情況

二、為什么不會 “回頭”?因為遞歸的 “調用棧” 是 “先進后出”

遞歸的執行依賴 “調用棧”,每個函數調用會入棧,執行完會出棧,出棧后就不會再重新入棧(除非有新的調用,但這道題沒有)。

還是以42為例:

  • 當調用invertTree(4)時,4的函數入棧;
  • 然后調用invertTree(2)(處理4的左子樹),2的函數入棧;
  • 再調用invertTree(1)(處理2的左子樹),1的函數入棧;
  • 1處理完(無交換),出棧,回到2的函數;
  • 2處理完(交換左右),出棧,回到4的函數;
  • 4處理完(交換左右),出棧,整個流程結束。

每個節點的函數一旦出棧,就意味著它的 “處理已完成”,后續不會再重新入棧處理 —— 所以不存在 “第二次回頭,root 已經變了” 的場景。

三、一句話總結

遞歸處理二叉樹時,每個節點只被 “訪問并交換一次”,處理順序是 “先處理所有子節點,再處理當前節點”,子節點處理完不會回頭,當前節點處理完也不會再被重新處理,因此無需擔心 “root 被修改后再次調用” 的問題。

【有點像祖瑪游戲一個一個珠子過去,root只走一遍,但是每一次左右都換了】

這個比喻太形象了!完全命中了遞歸處理的核心 ——每個 “珠子”(節點)只走一遍,走的時候就把自己的 “左右裝飾”(左右子樹)換好,之后再也不回頭。咱們再順著這個比喻補一層細節,幫你徹底敲定邏輯:

一、“祖瑪珠子” 對應遞歸的 “節點處理順序”

把整棵二叉樹想象成一串 “祖瑪珠子”,珠子的順序是「從根到最左子樹→回退到父節點→再到右子樹」(也就是遞歸的 “深度優先” 順序),每個珠子只被 “捏過一次”:

  1. 捏到一個珠子(比如節點2),先不換它的左右,而是先順著線捏它左邊的小珠子(1);
  2. 小珠子1沒有更小的珠子了(左右都是null),捏完直接放回去(無交換);
  3. 再捏2右邊的小珠子(3),同樣捏完放回去;
  4. 現在回到2這個珠子,這時候才把它的 “左珠” 和 “右珠”(13)對調,換完后2就處理完了,再也不碰;
  5. 接著回到上一顆大珠子(4),等它右邊的珠子(7)也按同樣邏輯捏完、換完,再把4的 “左珠”(換好的2)和 “右珠”(換好的7)對調。

二、“只走一遍” 對應 “節點不重復處理”

祖瑪游戲里珠子滾過就不會倒回來,遞歸里的節點也一樣:

  • 每個節點的 “交換左右” 操作,只會在 “所有子節點都處理完” 后執行一次;
  • 執行完交換,這個節點就作為 “處理好的成品”,傳遞給上一級節點(父節點),之后再也不會被這個遞歸流程重新訪問。
    比如節點2換完左右后,就變成了 “左3、右1” 的狀態,后續只有父節點4會把它當作 “成品珠子” 來用,不會再單獨拿出來重新換一次。

三、“每一次左右都換了” 對應 “遞歸的核心動作”

沒錯!每個珠子(非空節點)被 “捏到” 時,核心動作就是 “換左右”—— 但這個 “換” 是有前提的:

  • 必須等它左右兩邊的 “子珠子串” 都先換好(遞歸處理完左右子樹),再換自己的左右;
  • 換的時候用的是 “已經換好的子珠子串”(前兩行遞歸得到的leftright變量),不是沒處理過的原始子樹。

就像祖瑪里換珠子裝飾,得先把左右兩邊的小裝飾串做好,再往當前珠子上裝,裝完就固定了。

一句話收尾

你說的 “祖瑪珠子” 邏輯,完美對應了遞歸的「深度優先、節點唯一處理、先子后父交換”—— 每個節點只走一趟,走的時候就把左右換好,整個流程順下來,樹自然就翻過來了~

----------------------------------

最后手敲一遍吧!

/**
?* Definition for a binary tree node.
?* public class TreeNode {
?* ? ? int val;
?* ? ? TreeNode left;
?* ? ? TreeNode right;
?* ? ? TreeNode() {}
?* ? ? TreeNode(int val) { this.val = val; }
?* ? ? TreeNode(int val, TreeNode left, TreeNode right) {
?* ? ? ? ? this.val = val;
?* ? ? ? ? this.left = left;
?* ? ? ? ? this.right = right;
?* ? ? }
?* }
?*/
class Solution {
? ? public TreeNode invertTree(TreeNode root) {
? ? ? ? ? if (root == null){

? ? ? ? ? ? ? ? return null;

}

TreeNode left = invertTree(root.left);

TreeNode right?= invertTree(root.right);

root.left = right;

root.right = left;

return root;


? ? }
}

加油!(? ?_?)?

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

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

相關文章

嵌入式學習的第四十九天-時鐘+EPIT+GPT定時器

一、時鐘1.時鐘系統基本概念&#xff08;1&#xff09;PLL (鎖相環, Phase-Locked Loop)作用&#xff1a;PLL是一種反饋控制電路&#xff0c;用于生成穩定的高頻時鐘信號。它通過將輸出時鐘與參考時鐘進行比較和調整&#xff0c;可以產生比輸入參考時鐘頻率高得多的輸出時鐘。倍…

Python Sqlalchemy數據庫連接

Python Sqlalchemy數據庫連接一、連接數據二、模型三、ORM操作一、連接數據 from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker# 1. 連接數據庫 dbHost postgres://用戶名:密碼主機:端口/數據庫名 engine create_engine(dbHost) # create_engi…

【Node.js】ECMAScript標準 以及 npm安裝

目錄 一、 ECMAScript標準 - 默認導出和導入 二、ECMAScript標準 - 命名導出和導入 三、包的概念 五、 npm - 安裝所有依賴 六、 npm - 全局軟件包 Node.js總結 總結不易~ 本章節對我有很大的收獲&#xff0c; 希望對你也是&#xff01;&#xff01;&#xff01; 本節素材…

NPM 、 NPX

NPM vs. NPX 簡單來說&#xff0c;npm 是一個 node 包管理器&#xff0c;npx 是一個 Node 包執行器。 NPX 是一個 Node 包執行器&#xff0c;該 Node 包可以是本地也可以是遠程的。允許開發者在無需安裝的情況下執行任意 Node 包。npm 在安裝nodejs 就自動帶了 npm install -g …

守護品質安全,防偽溯源系統打造全鏈路信任體系

一、引言在當下這個信息透明、品質至上的時代&#xff0c;防偽溯源已經成為眾多品牌保護自身利益、提升消費者信任度的重要手段。為了滿足市場上對高效、可靠的防偽溯源查詢系統的迫切需求&#xff0c;榕壹云精心打造了一款防偽溯源查詢系統。二、項目背景隨著商品市場的不斷擴…

【完整源碼+數據集+部署教程】無人機航拍視角洪水檢測與受災房屋識別圖像分割救援指導系統源碼和數據集:改進yolo11-DCNV2

背景意義 研究背景與意義 隨著全球氣候變化的加劇&#xff0c;極端天氣事件的頻率和強度不斷上升&#xff0c;洪水作為一種常見的自然災害&#xff0c;給人類社會帶來了嚴重的威脅。洪水不僅導致人員傷亡和財產損失&#xff0c;還對基礎設施和生態環境造成了深遠的影響。因此&a…

C# 結構體與類的區別是什么?

結構體是值類型是儲存在棧中獨立儲存的,數據與數據之間不會相互影響,即使將一個結構體賦值給另外一個結構體也不會相互影響。 類是一個模板,實例出來的對象是獨立的不會相互影響,但是將一個對象賦值給另一個對象時 會把指向堆內存中數據的指針賦值給另一個對象.從而發生兩個變量…

Redis GEO

Redis GEO 引言 Redis 是一款高性能的鍵值存儲系統,廣泛應用于緩存、消息隊列等領域。Redis GEO 是 Redis 2.4 版本后新增的一個功能,用于存儲地理位置信息。本文將詳細介紹 Redis GEO 的概念、使用方法以及應用場景。 什么是 Redis GEO? Redis GEO 是 Redis 的一個模塊…

Go從入門到精通系列學習路線規劃

Go從入門到精通系列學習路線規劃 目錄導航 Go從入門到精通系列學習路線規劃首頁說明 第1篇_Go語言初探_環境搭建與HelloWorld 第2篇_Go語言基礎語法_變量常量與數據類型 第3篇_Go語言控制結構_條件判斷與循環 第4篇_Go語言函數詳解 第5篇_Go語言數據結構詳解 第6篇_Go語言結構體…

Grid系統概述

目錄 概念及功能 網格對象&#xff08;Grid Object&#xff09; 和世界對象&#xff08;World Object&#xff09; 工作流程 概念及功能 TrinityCore 的 Grid 系統是一套復雜的地圖分區管理機制&#xff0c;其核心目標是通過動態管控游戲世界的區域狀態和對象生命周期&#…

一文搞懂LLM大模型!LLM從入門到精通萬字長文(2024.12月最新)

LLM從入門到精通精品文章 目錄 一、LLM基本概念 二、LLM發展歷程 三、LLM大模型的分類 四、LLM主流大模型類別 五、LLM大模型建立的流程 六、Fine-Tuning 七、Prompt-Tuning 八、超大規模參數模型Prompt-Tuning方法 8.1上下文學習 In-Context Learning 8.2.指令學習 …

Next.js跟React關系(Next.js是基于React庫的全棧框架)(文件系統路由、服務端渲染SSR、靜態生成SSG、增量靜態再生ISR、API路由)

文章目錄**1. React 是基礎&#xff0c;Next.js 是擴展****2. Next.js 解決了 React 的哪些痛點&#xff1f;****3. 核心區別****4. Next.js 的核心特性**1. **文件系統路由**2. **服務端渲染&#xff08;SSR&#xff09;**3. **靜態生成&#xff08;SSG&#xff09;**4. **增量…

Nightingale源碼Linux進行跨平臺編譯

最近使用Nightingale 需要實現對服務的監測&#xff0c;想要在Windows 系統中使用&#xff0c;看官方文檔中并不直接提供執行程序&#xff0c;原文如下&#xff1a; 準備工作 本地環境 本地已經安裝git 本地安裝git 便于后續下載源碼并進行自動編譯。 Linux操作系統環境&…

抽絲剝繭丨PostgreSQL 系國產數據庫%SYS CPU newfstatat() high 調優一例(二)

續接上回《PostgreSQL 系國產數據庫%SYS CPU newfstatat() high 調優一例&#xff08;一&#xff09;》&#xff0c;這個問題還在持續&#xff0c;并且原因并不只是一個&#xff0c;從調了文件系統級atime&#xff0c;到調整wal size減少日志被動清理&#xff0c;還有在驗證tem…

【新手入門】Android Studio 項目結構拆解,快速理解文件作用!

目 錄 一、【Project】視圖下項目結構&#xff08;真實目錄&#xff09; 二、【Android】視圖下項目結構 三、【app/】下重要文件解析 1、 build.gradle 2、AndroidManifest.xml 3、res/ 作為剛剛接觸Android開發的小白&#xff0c;使用Android Studio創建項目后&…

Python實現點云Kmeans、歐式和DBSCAN聚類

本節我們分享點云處理中的三種常見聚類方法&#xff0c;分別是K-means、歐氏與 DBSCAN聚類。具體介紹如下&#xff1a;1. K-means 聚類定義&#xff1a;一種基于距離度量的無監督學習算法&#xff0c;將數據劃分為 K 個緊湊的簇&#xff0c;使簇內數據相似度高、簇間差異大。算…

【Java后端】MyBatis-Plus 原理解析

MyBatis-Plus 原理解析 其實 MyBatis-Plus 的 Service 層設計就是為了讓開發者不用重復寫很多樣板代碼。我們來一點點剖析 UserServiceImpl、IService、UserService、ServiceImpl 之間的關系和調用鏈。1. 類/接口關系圖IService<T>▲│UserService (接口) <-- 自定義…

Nacos 注冊中心學習筆記

&#x1f389; Alibaba微服務組件 Nacos 注冊中心超詳細學習筆記 &#x1f389; &#x1f4cc; 寫在前面&#xff1a;本文基于官方PDF文檔與實戰經驗&#xff0c;整理了Nacos注冊中心的核心知識點、部署流程與實戰技巧&#xff0c;力求圖文并茂、通俗易懂&#xff0c;適合收藏反…

java 策略模式 demo

策略模式介紹策略模式&#xff08;Strategy Pattern&#xff09;是一種行為型設計模式&#xff0c;它定義了一系列算法&#xff0c;將每個算法封裝起來并使它們可相互替換。策略模式讓算法的變化獨立于使用算法的客戶端&#xff0c;從而實現靈活的算法切換。核心角色&#xff1…

SAP Valuation Category在制造業成本核算中的使用場景與配置方案

Valuation Category在制造業成本核算中的使用場景與配置方案一、核心使用場景&#xff08;制造業特有&#xff09;1. 內制 vs 外購成本分離業務需求&#xff1a;同一物料可能通過內部生產&#xff08;成本含料工費&#xff09;或外部采購&#xff08;成本含采購價運費&#xff…