102. 二叉樹的層序遍歷遞歸法:深度優先搜索的巧妙應用

二叉樹的層序遍歷是一種經典的遍歷方式,它要求按層級逐層訪問二叉樹的節點。通常我們會使用隊列來實現層序遍歷,但遞歸法也是一種可行且有趣的思路。本文將深入探討遞歸法解決二叉樹層序遍歷的核心難點,并結合代碼和模擬過程進行詳細講解。

一、題目描述

給定一個二叉樹的根節點 root,返回其節點值的層序遍歷結果,即逐層遍歷,從左到右訪問所有節點。例如,輸入二叉樹:

    3/ \9  20/  \15   7

輸出結果應為:
[[3], [9, 20], [15, 7]]

二、核心難點分析

難點1:臨時數組的創建邏輯

在遞歸法中,我們需要預先創建好數組來存儲每一層的節點值。這里的關鍵是如何根據當前節點的深度(層級)來確定將節點值存儲到哪個數組中。

  • 深度標記
    我們使用一個變量 deep 來表示當前節點所在的深度。初始時,根節點的深度為 1
  • 數組創建與填充
    在遞歸過程中,每當遇到一個新的深度 deep 時,我們需要確保 res 中已經有足夠的子列表來存儲該層的節點值。如果 res 的大小小于 deep,則創建一個新的空列表并添加到 res 中。然后,將當前節點的值添加到 res 中對應深度的子列表中。

難點2:遞歸的具體邏輯實現

遞歸法的核心在于如何通過遞歸調用自身來遍歷二叉樹的每一層。

  • 遞歸終止條件
    當遇到 null 節點時,遞歸結束。這是因為 null 節點沒有值,也沒有子節點,不需要進行任何處理。
  • 遞歸調用
    對于每個非 null 節點,我們先將其值添加到對應深度的子列表中,然后分別對其左子節點和右子節點進行遞歸調用。在遞歸調用時,深度 deep 需要加 1,以表示進入了下一層。

三、解題思路分步解析

步驟1:初始化結果列表和遞歸調用

public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> res = new ArrayList<>();levelOrderBFS(res, root, 0);return res;
}

這里我們首先創建了一個空的結果列表 res,然后調用遞歸函數 levelOrderBFS 開始遍歷。初始深度設為 0,因為在遞歸函數內部會先將深度加 1 再進行處理。

步驟2:遞歸函數實現

public void levelOrderBFS(List<List<Integer>> res, TreeNode root, int deep) {if (root == null) {return;}deep++;while (res.size() < deep) {List<Integer> resList = new ArrayList<>();res.add(resList);}res.get(deep - 1).add(root.val);levelOrderBFS(res, root.left, deep);levelOrderBFS(res, root.right, deep);
}
  • 深度處理
    首先將深度 deep1,因為當前節點的深度比其父節點大 1
  • 數組創建與填充
    使用 while 循環檢查 res 的大小是否小于 deep。如果是,則創建一個新的空列表 resList 并添加到 res 中。這確保了 res 中始終有足夠的子列表來存儲每一層的節點值。
    然后,通過 res.get(deep - 1).add(root.val) 將當前節點的值添加到 res 中對應深度的子列表中。
  • 遞歸調用
    最后,分別對當前節點的左子節點和右子節點進行遞歸調用,深度 deep 保持不變。這使得遞歸能夠逐層深入,遍歷整個二叉樹。

四、遞歸流程模擬

以二叉樹 [3, 9, 20, null, null, 15, 7] 為例,結構如下:

    3/ \9  20/  \15   7

以下是遞歸過程的詳細模擬:

初始狀態

res = []deep = 0root = 3

第一次遞歸調用

  • deep = 1
  • res.size() = 0 < 1,創建新列表 [] 并添加到 res 中,此時 res = [[]]
  • 3 添加到 res[0] 中,此時 res = [[3]]
  • root.left(即 9)進行遞歸調用,deep = 1
  • root.right(即 20)進行遞歸調用,deep = 1

9 的遞歸調用

  • deep = 2
  • res.size() = 1 < 2,創建新列表 [] 并添加到 res 中,此時 res = [[3], []]
  • 9 添加到 res[1] 中,此時 res = [[3], [9]]
  • root.left(即 null)進行遞歸調用,deep = 2
  • root.right(即 null)進行遞歸調用,deep = 2

20 的遞歸調用

  • deep = 2
  • res.size() = 2 == 2,直接將 20 添加到 res[1] 中,此時 res = [[3], [9, 20]]
  • root.left(即 15)進行遞歸調用,deep = 2
  • root.right(即 7)進行遞歸調用,deep = 2

15 的遞歸調用

  • deep = 3
  • res.size() = 2 < 3,創建新列表 [] 并添加到 res 中,此時 res = [[3], [9, 20], []]
  • 15 添加到 res[2] 中,此時 res = [[3], [9, 20], [15]]
  • root.left(即 null)進行遞歸調用,deep = 3
  • root.right(即 null)進行遞歸調用,deep = 3

7 的遞歸調用

  • deep = 3
  • res.size() = 3 == 3,直接將 7 添加到 res[2] 中,此時 res = [[3], [9, 20], [15, 7]]
  • root.left(即 null)進行遞歸調用,deep = 3
  • root.right(即 null)進行遞歸調用,deep = 3

最終結果

res = [[3], [9, 20], [15, 7]]

五、關鍵知識點總結

1. 遞歸的基本概念

遞歸是一種解決問題的方法,它通過將問題分解為更小的子問題,并通過調用自身來解決這些子問題。在二叉樹的層序遍歷中,我們通過遞歸調用自身來遍歷每一層的節點。

2. 深度優先搜索(DFS)與廣度優先搜索(BFS)

遞歸法本質上是一種深度優先搜索(DFS)的應用。與廣度優先搜索(BFS)不同,DFS會沿著一條路徑一直深入下去,直到無法繼續,然后再回溯到上一層,繼續探索其他路徑。在層序遍歷中,我們通過遞歸實現了一種特殊的DFS,它能夠逐層遍歷二叉樹的節點。

3. 動態數組的使用

在遞歸過程中,我們使用了一個動態數組 res 來存儲每一層的節點值。動態數組的特點是可以根據需要動態地增加或減少元素,這使得我們能夠靈活地處理不同層級的節點數量。

六、完整代碼

import java.util.ArrayList;
import java.util.List;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 List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> res = new ArrayList<>();levelOrderBFS(res, root, 0);return res;}public void levelOrderBFS(List<List<Integer>> res, TreeNode root, int deep) {if (root == null) {return;}deep++;while (res.size() < deep) {List<Integer> resList = new ArrayList<>();res.add(resList);}res.get(deep - 1).add(root.val);levelOrderBFS(res, root.left, deep);levelOrderBFS(res, root.right, deep);}
}

七、總結

遞歸法解決二叉樹的層序遍歷問題雖然不像隊列法那樣直觀,但它展示了深度優先搜索在樹形結構中的巧妙應用。通過理解臨時數組的創建邏輯和遞歸的具體實現,我們能夠更好地掌握遞歸的思想和技巧。在實際應用中,遞歸法可能在某些情況下比隊列法更簡潔高效,尤其是對于一些復雜的樹形結構或需要深度優先處理的問題。希望本文的講解能夠幫助讀者更好地理解和掌握遞歸法解決二叉樹層序遍歷的核心難點。

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

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

相關文章

首個窗口級無人機配送VLN系統!中科院LogisticsVLN:基于MLLM實現精準投遞

導讀 隨著智能物流需求日益增長&#xff0c;特別是“最后一公里”配送場景的精細化&#xff0c;傳統地面機器人逐漸暴露出適應性差、精度不足等瓶頸。為此&#xff0c;本文提出了LogisticsVLN系統——一個基于多模態大語言模型的無人機視覺語言導航框架&#xff0c;專為窗戶級別…

WPF Datagrid 數據加載和性能

這篇文章并非討論 WPF Datagrid 的性能數據&#xff0c;而只是簡單介紹一下為了使其性能良好&#xff0c;你需要注意哪些方面。我不太想使用性能分析器來展示實際數據&#xff0c;而是盡可能地使用了 Stopwatch 類。這篇文章不會深入探討處理海量數據的技術&#xff0c;例如分頁…

matlab求矩陣的逆、行列式、秩、轉置

inv - 計算矩陣的逆 用途&#xff1a;計算一個可逆矩陣的逆矩陣。 D [1, 2; 3, 4]; % 定義一個2x2矩陣 D_inv inv(D); % 計算矩陣D的逆 disp(D_inv);det - 計算矩陣的行列式 用途&#xff1a;計算方陣的行列式。 E [1, 2; 3, 4]; determinant det(E); % 計算行列式 disp…

ridecore流水線解讀

文章目錄 流水線stage分屬前后端PCpipelineIFIDDPDP 與 SW 中間沒有latchSWCOM 源碼地址 流水線stage分屬前后端 IF -> ID -> DP -> SW -> EX -> COM分類階段說明前端IF指令獲取階段。PC 使用分支預測器&#xff0c;訪問指令存儲器。典型前端操作。前端ID解碼并…

【SpringBoot】關于MP使用中配置了數據庫表前綴的問題

problem 使用MP時&#xff0c;在application.yml配置文件中配置了MP匹配數據庫表中的表名時的前綴作了規定&#xff0c;如下&#xff1a; 那么當我運行時報錯了錯誤&#xff0c;報錯信息如下&#xff1a; 因為我數據庫表的書類表名是book&#xff0c;MP在匹配時使用了表名前…

印度Rummy游戲支付通道申請策略:技巧類游戲的合規與創新

本文為印度支付申請科普文&#xff0c;自去年開始&#xff0c;印度Rummy類游戲申請印度支付都需要擁有AIGF的會員及產品證書。 如需要rummy可以通過AIGF審核的源。碼&#xff0c;或咨詢AIGF的相關內容&#xff0c;可以聯。系老妙。 印度作為全球棋牌類游戲增長最快的市場之一&…

日志與策略模式

什么是設計模式 IT?業 ,為了讓 菜雞們不太拖?佬的后腿, 于是?佬們針對?些經典的常?的場景, 給定了?些對應的解決?案, 這個就是 設計模式 日志認識 計算機中的?志是記錄系統和軟件運?中發?事件的?件&#xff0c;主要作?是監控運?狀態、記錄異常信 息&#xff…

解鎖Ubuntu高效部署!自動安裝配置文件YAML全解析

我們之前介紹了兩種Ubuntu系統的安裝方式&#xff0c;分別對應桌面版&#xff08;準備搞OpenStack了&#xff0c;先裝一臺最新的Ubuntu 23.10&#xff09;和服務器版&#xff08;Ubuntu 22.04 LTS服務器版本安裝演示&#xff09;。但對于有些用戶&#xff0c;因為技術問題&…

關系代數和關系數據庫語言(SQL)

閱讀提示&#xff1a;本篇文章較長&#xff0c;建議從目錄上選取想看的內容。代碼上的話&#xff0c;我習慣用小寫&#xff0c;如果看不習慣建議跳過。有問題歡迎討論&#xff01;&#xff01;&#xff01; 一、基礎概念 1.1數據庫的概念 數據庫(Database)是按照數據結構來組…

EXO 可以將 Mac M4 和 Mac Air 連接起來,并通過 Ollama 運行 DeepSeek 模型

EXO 可以將 Mac M4 和 Mac Air 連接起來&#xff0c;并通過 Ollama 運行 DeepSeek 模型。以下是具體實現方法&#xff1a; 1. EXO 的分布式計算能力 EXO 是一個支持 分布式 AI 計算 的開源框架&#xff0c;能夠將多臺 Mac 設備&#xff08;如 M4 和 Mac Air&#xff09;組合成…

區塊鏈基本理解

文章目錄 前言一、什么是分布式賬本(DLT)二、什么是P2P網絡?二、共識算法三、密碼算法前言 區塊鏈是由一個一個數據塊組成的鏈條,按照時間順序將數據塊逐一鏈接,通過哈希指針鏈接,所有的數據塊共同維護一份分布式賬本(DLT),每個節點(可以理解為一個玩家,一臺計算機)都擁…

Node.js中的洋蔥模型

文章目錄 前言 前言 Node.js中的洋蔥模型是一種中間件執行機制&#xff0c;主要用于處理HTTP請求和響應的流程控制。該模型通過層層包裹的中間件結構&#xff0c;實現請求從外到內穿透、響應從內向外返回的順序執行。以下從核心概念、實現原理、框架差異及實際應用等方面解析&…

UI-TARS Desktop:用自然語言操控電腦,AI 重新定義人機交互

在人工智能技術飛速發展的今天,從文本生成到圖像識別,AI 的能力邊界不斷被打破。而字節跳動近期開源的 UI-TARS Desktop,則將這一技術推向了更復雜的交互場景——通過自然語言直接控制計算機界面,實現了圖形用戶界面(GUI)的智能化自動化。這款工具不僅降低了操作門檻,更…

一個可拖拉實現列表排序的WPF開源控件

從零學習構建一個完整的系統 推薦一個可通過拖拉&#xff0c;來實現列表元素的排序的WPF控件。 項目簡介 gong-wpf-dragdrop是一個開源的.NET項目&#xff0c;用于在WPF應用程序中實現拖放功能&#xff0c;可以讓開發人員快速、簡單的實現拖放的操作功能。 可以在同一控件內…

C語言中字符串函數的詳細講解

C語言提供了豐富的字符串處理函數&#xff0c;這些函數在<string.h>頭文件中聲明。以下是一些常用字符串函數的詳細講解&#xff1a; 字符串拷貝函數 strcpy 功能&#xff1a;將源字符串&#xff08;包括結尾的\0&#xff09;復制到目標字符串。原型&#xff1a;char *s…

可視化數據圖表怎么做?如何實現三維數據可視化?

目錄 一、三維數據可視化的要點 1. 明確數據可視化的目標 2. 篩選與整理數據 3. 選擇合適的圖表類型 4. 運用專業工具制作 5. 優化圖表的展示效果 二、數據可視化圖表怎么做&#xff1f; 1. 理解三維數據的特性 2. 數據處理與三維建模 3. 設置光照與材質效果 4. 添加…

在Linux服務器上部署Jupyter Notebook并實現ssh無密碼遠程訪問

Jupyter notebook版本7.4.2&#xff08;這個版本AI提示我Jupyter7&#xff08;底層是 jupyter_server 2.x&#xff09; 服務器開啟服務 安裝Jupyter notebook 7.4.2成功后&#xff0c;終端輸入 jupyter notebook --generate-config 這將在 ~/.jupyter/ 目錄下生成 jupyter_…

走出 Demo,走向現實:DeepSeek-VL 的多模態工程路線圖

目錄 一、引言&#xff1a;多模態模型的關鍵轉折點 &#xff08;一&#xff09;當前 LMM 的三個關鍵挑戰 1. 數據的真實性不足 2. 模型設計缺乏場景感知 3. 語言能力與視覺能力難以兼顧 &#xff08;二&#xff09;DeepSeek-VL 的根本出發點&#xff1a;以真實任務為錨點…

數據庫原理及其應用 第六次作業

題目 參考答案 題目1. 教材P148第1題 問題&#xff1a;什么是數據庫的安全性&#xff1f; 答案&#xff1a;數據庫的安全性是指保護數據庫以防止不合法的使用所造成的數據泄露、更改或破壞 。它通過用戶身份鑒別、存取控制&#xff08;包括自主存取控制和強制存取控制&#x…

2025系統架構師---選擇題知識點(押題)

1.《計算機信息系統安全保護等級劃分準則》(GB 17859-1999)由低到高定義了五個不同級別的計算機系統安全保護能力。 第一級:用戶自主保護級---通過隔離用戶與數據實現訪問控制,保護用戶信息安全; 第二級:系統審計保護級---實施更細粒度的訪問控制,通過審計和隔離資源確…