二叉樹深搜:在算法森林中尋找路徑

專欄:算法的魔法世界

個人主頁:手握風云

目錄

一、搜索算法

二、回溯算法

三、例題講解

3.1.?計算布爾二叉樹的值

3.2.?求根節點到葉節點數字之和

3.3.?二叉樹剪枝

3.4.?驗證二叉搜索樹

3.5.?二叉搜索樹中第 K 小的元素

3.6.?二叉樹的所有路徑


一、搜索算法

  • BFS和DFS

? ? ? ? 廣度優先搜索(BFS)和深度優先搜索(DFS)是兩種常用的圖和樹的遍歷算法,遍歷是形式,目的是搜索,在某種形式上,遍歷算法與搜索算法可以等價。

????????BFS 的核心思想是從一個節點開始,逐層遍歷所有可達的節點,直到找到目標節點或遍歷完所有節點。DFS 的核心思想是從一個節點開始,沿著一條路徑盡可能深地搜索,直到無法繼續前進時,再回溯到上一個節點,繼續搜索其他路徑。

  • 暴搜

? ? ? ? 暴力搜索是一種簡單的搜索方式,通過暴力枚舉所有的情況來找出結果,通常基于BFS和DFS實現。暴力搜索通常應用于用于解決那些沒有明顯規律或優化方法的問題,尤其是在數據規模較小時,但有時效率會特別低。

二、回溯算法

? ? ? ? 回溯算法是一種通過遞歸搜索所有可能的候選解來找出所有解的算法,它沒有那么神秘,本質上其實就是DFS。回溯算法通常可用于迷宮求解,如下圖所示,從起點進入并走出迷宮,按照深搜的思路,沿著一條路徑走。如果是死胡同,就回溯走另一條路徑,再次按照DFS,遞歸搜索和回溯找到迷宮出口。如果在搜索之前,我們知道這個答案不是我們想要的,我們就直接可以舍棄,這個過程就叫剪枝。

三、例題講解

3.1.?計算布爾二叉樹的值

????????本題中給出的是完整二叉樹,要么沒有節點,要么左右孩子節點都有。其中葉子節點儲存的是真值,非葉子節點儲存的是邏輯與、或。我們以示例1為例,0合取1,結果為0;0析取1,結果為1,返回真。

????????宏觀角度:從上面的示例中我們可以得出,這棵樹是從下往上推導的。當我們只看根節點時,我們得知道左子樹的值,同時也得知道右子樹的值,然后在根節點這一層進行整合。而關于求出左右子樹的布爾值,與前面的問題是一樣的,只需要傳入一個引用,即可返回布爾值,這就是遞歸方法頭與方法體的設計。當我們遍歷到葉子節點時,不需要判斷它的左右子樹是否為空,只需要進行邏輯運算即可,這同時也是遞歸的出口。

? ? ? ? 細節角度:因為計算過程是從下往上,我們可以看作是二叉樹的后序遍歷。從根節點出發,先去遍歷左子樹,當遇到葉子節點時,返回該節點的布爾值,然后回溯到它的父親節點,然后遍歷右子樹,再回溯父親節點并遍歷自身。

? ? ? ? 完整代碼實現:

/*** 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 boolean evaluateTree(TreeNode root) {if (root.left == null) {return root.val == 1;}boolean left = evaluateTree(root.left);boolean right = evaluateTree(root.right);return root.val == 2 ? (left || right) : (left && right);}
}

3.2.?求根節點到葉節點數字之和

? ? ? ? 需要計算出從根節點出發到所有葉子節點的每一條路徑所表示的數字,然后將這些數字相加,得到的總和就是最終要求的結果。即要找出二叉樹中所有從根到葉子的路徑所對應的數字,并把它們累加起來。

? ? ? ? 以下圖為例,當我們遞歸到“9”這一層時,我們就需要把“4”先傳進來,計算得到49。再把"49"繼續向下遞歸,計算得到495、491,然后返回,直到返回到根結點。那遞歸的方法頭可以設計兩個參數,一個根結點和一個路徑和presum,返回值為根結點所連接的葉子結點的數字之和。方法體的執行下圖中的4步。遞歸的出口則為遇到葉子結點時,返回路徑之和。

? ? ? ? 完整代碼實現:

/*** 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 int sumNumbers(TreeNode root) {return dfs(root,0);}private int dfs(TreeNode root,int preSum) {preSum = preSum * 10 + root.val;if (root.left == null && root.right == null) {return preSum;}int ret = 0;if (root.left != null) ret += dfs(root.left,preSum);if (root.right != null) ret += dfs(root.right,preSum);return ret;}
}

3.3.?二叉樹剪枝

? ? ? ? 題目要求移除所有不包含1的子樹,也就是說,如果一個節點沒有任何子節點且其值為0,那么這個節點就應該被刪除。

? ? ? ? 如果我們想剪掉某一棵子樹,必須先知道左右子樹的信息,所以我們一定是要采用后序遍歷來實現。當我們遍歷到某一節點時,如果發現左右子樹均為空,并且節點值為0,那我們就可以把這個節點剪掉。而我們返回它的父親節點時,需要加一個返回值將其置為空,然后繼續判斷。如果節點值為1,那我們就直接返回它的父親節點就可以了。那我們設計遞歸方法的時候,只需傳入一個根節點,然后去遍歷它的左右子樹,根據返回值來判斷是否該剪掉。

/*** 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 pruneTree(TreeNode root) {if (root == null) {return null;}root.left = pruneTree(root.left);root.right = pruneTree(root.right);if (root.left == null && root.right == null && root.val == 0) {root = null;}return root;}
}

3.4.?驗證二叉搜索樹

? ? ? ? 根據前面學過的知識,對一棵二叉搜索樹進行中序遍歷,得到的結果是一個有序序列,所以我們可以先定義一個全局變量prev,當遍歷到某一個節點時,用prev存儲前一個節點值,如下圖所示,根據中序遍歷,當我們遍歷到1時,將prev賦值為1,然后進行比較,后面的數如果越來越大,那就是二叉搜索樹。當遍歷到19時,會發現19比20小,整棵樹就不是二叉搜索樹。那么我們就可以通過剪枝,省去處理右子樹的過程,直接向上返回一個false。

? ? ? ? 完整代碼實現:

/*** 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 {long prev = Long.MIN_VALUE;public boolean isValidBST(TreeNode root) {if (root == null) return true;boolean left = isValidBST(root.left);//剪枝if(left == false) return false;boolean cur = false;if (root.val > prev) cur = true;prev = root.val;boolean right = isValidBST(root.right);return left && cur && right;}
}

3.5.?二叉搜索樹中第 K 小的元素

? ? ? ? 仿照上一題的思路,利用兩個全局變量,其中一個變量是在中序遍歷時充當計數器,另一個變量去標記第K小的結果。進行中序遍歷,當遍歷到第一個節點時,count--,直到count=0時,說明已經到了第k個節點,此時進行剪枝,把ret更新為17,無需遍歷其它子樹。

/*** 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 {int count;int ret;public int kthSmallest(TreeNode root, int k) {count = k;InOrder(root);return ret;}public void InOrder(TreeNode root) {if (root == null || count == 0) return;InOrder(root.left);count--;if (count == 0) ret = root.val;if (count == 0) return;InOrder(root.right);}
}

3.6.?二叉樹的所有路徑

????????給定一個二叉樹的根節點,然后找出所有從根節點到葉子節點的路徑。每條路徑都應該以字符串的形式返回,路徑中的節點值之間用箭頭“->”連接。

? ? ? ? 我們先弄一個字符串變量path,在進行前序遍歷的時候,記錄每個路徑的字符串,當遇到葉子節點時,丟進順序表List<String> ret中。但如果我們遍歷完一條路徑后,回溯就會出現問題,比如我們遍歷完"1->2->4",回溯到節點2時,也會返回這個結果,所以我們還需要進行恢復現場的操作,把字符4移除。當我們把節點2處理完返回到節點1時,我們需要移除的是"2->",所以這個過程就會非常麻煩。我們可以把這個變量放在遞歸方法的參數里,那我們的方法頭就可以設計成DFS(root,path)。當遞歸方法執行的時候,如果是葉子節點,不需要加上"->";如果不是葉子節點,需要加上"->"。當某個節點的左子樹為空而右子樹不為空,那就不需要執行DFS(root.right,path),直接返回。

? ? ? ? 完整代碼實現:

/*** 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 {List<String> ret;public List<String> binaryTreePaths(TreeNode root) {ret = new ArrayList<>();DFS(root,new StringBuffer());return ret;}public void DFS(TreeNode root,StringBuffer _path) {StringBuffer path = new StringBuffer(_path);path.append(Integer.toString(root.val));if (root.left == null && root.right == null) {ret.add(path.toString());return;}path.append("->");if (root.left != null) DFS(root.left,path);if (root.right != null) DFS(root.right,path);}
}

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

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

相關文章

企業級AI搜索解決方案:阿里云AI搜索開放平臺

隨著信息技術的飛速發展&#xff0c;搜索引擎作為信息獲取的重要工具&#xff0c;扮演著不可或缺的角色。阿里云 AI 搜索開放平臺以其強大的技術支持和靈活的開放性&#xff0c;持續為用戶提供高效的搜索解決方案。 一、阿里云 AI 搜索開放平臺 一站式的 AI 搜索開放平臺作為…

自動駕駛中的預測控制算法:用 Python 讓無人車更智能

自動駕駛中的預測控制算法:用 Python 讓無人車更智能 自動駕駛技術近年來取得了令人驚嘆的進步,AI 與邊緣計算的結合讓車輛能夠實時感知環境、規劃路徑并執行駕駛決策。其中,預測控制(Model Predictive Control,MPC) 作為一種先進的控制算法,憑借其對未來駕駛行為的優化…

量子計算機超越超級計算機——它們解決了哪些問題?

“ 南加州大學的研究人員取得了重大突破&#xff0c;證明量子計算機在解決某些復雜問題時甚至可以勝過最快的超級計算機。” 量子退火最終顯示出擴展優勢&#xff0c;得益于錯誤抑制的量子處理&#xff0c;它比傳統超級計算機提供更快、接近最優的解決方案。 南加州大學的研究人…

Java虛擬機 -方法調用

方法調用 方法調用靜態鏈接動態鏈接案例虛方法與非虛方法虛方法&#xff08;Virtual Method&#xff09;非虛方法&#xff08;Non-Virtual Method&#xff09; 方法返回地址 方法調用 我們編寫Java程序的時候&#xff0c;我們自己寫的類通常不僅僅是調用自己本類的方法。調用別…

【 開源:跨平臺網絡數據傳輸的萬能工具libcurl】

在當今這個互聯互通的世界中&#xff0c;數據在各種設備和平臺之間自由流動&#xff0c;而 libcurl&#xff0c;就像一把跨平臺的萬能工具&#xff0c;為開發者提供了處理各種網絡數據傳輸任務所需的強大功能。它不僅是一個庫&#xff0c;更是一種通用的解決方案&#xff0c;可…

ElasticSearch 8.x 快速上手并了解核心概念

目錄 核心概念概念總結 常見操作索引的常見操作常見的數據類型指定索引庫字段類型mapping查看索引庫的字段類型最高頻使用的數據類型 核心概念 在新版Elasticsearch中&#xff0c;文檔document就是一行記錄(json)&#xff0c;而這些記錄存在于索引庫(index)中, 索引名稱必須是…

優化 CRM 架構,解鎖企業競爭力密碼

引言 “在所有企業面臨的挑戰中&#xff0c;客戶關系管理無疑是最為關鍵的一環。” —— 彼得德魯克 在數字化浪潮席卷的當下&#xff0c;企業面臨著前所未有的機遇與挑戰。客戶關系管理&#xff08;CRM&#xff09;作為企業運營的核心環節&#xff0c;其架構的優劣直接影響著…

深入理解Docker和K8S

深入理解Docker和K8S Docker 是大型架構的必備技能&#xff0c;也是云原生核心。Docker 容器化作為一種輕量級的虛擬化技術&#xff0c;其核心思想&#xff1a;將應用程序及其所有依賴項打包在一起&#xff0c;形成一個可移植的單元。 容器的本質是進程&#xff1a; 容器是在…

list.forEach(s -> countService.refreshArticleStatisticInfo(s.getId())); 講解一下語法

這段代碼使用了Java中的forEach方法結合Lambda表達式來遍歷一個列表&#xff0c;并對列表中的每個元素執行特定操作。具體來說&#xff0c;它會遍歷列表中的每一個元素&#xff0c;并調用countService.refreshArticleStatisticInfo(s.getId())方法來刷新每個文章的統計信息。下…

AI開發者的算力革命:GpuGeek平臺全景實戰指南(大模型訓練/推理/微調全解析)

目錄 背景一、AI工業化時代的算力困局與破局之道1.1 中小企業AI落地的三大障礙1.2 GpuGeek的破局創新1.3 核心價值 二、GpuGeek技術全景剖析2.1 核心架構設計 三、核心優勢詳解?3.1 優勢1&#xff1a;工業級顯卡艦隊???3.2 優勢2&#xff1a;開箱即用生態?3.2.1 預置鏡像庫…

05算法學習_59. 螺旋矩陣 II

05算法學習_59. 螺旋矩陣 II 05算法學習_59. 螺旋矩陣 II題目描述&#xff1a;個人代碼&#xff1a;學習思路&#xff1a;第一種寫法&#xff1a;題解關鍵點&#xff1a; 個人學習時疑惑點解答&#xff1a; 05算法學習_59. 螺旋矩陣 II 力扣題目鏈接: 59. 螺旋矩陣 II 題目描…

JDK7Hashmap的頭插法造成的環問題

單線程下的擴容 多線程下的擴容 next&#xff1d;e 然后e的next變成e

JAVA|后端編碼規范

目錄 零、引言 一、基礎 二、集合 三、并發 四、日志 五、安全 零、引言 規范等級&#xff1a; 【強制】&#xff1a;強制遵守&#xff0c;來源于線上歷史故障&#xff0c;將通過工具進行檢查。【推薦】&#xff1a;推薦遵守&#xff0c;來源于日常代碼審查、開發人員反饋…

2025-05-21 Python深度學習5——數據讀取

文章目錄 1 數據準備2 Dataset2.1 自定義 Dataset2.2 使用示例 3 TensorBoard3.1 安裝3.2 標量可視化&#xff08;Scalars&#xff09;3.3 圖像可視化&#xff08;Images&#xff09;3.4 其他常用功能 4 transform4.1 ToTensor()4.2 Normalize()4.3 Resize()4.4 Compose()4.5 C…

5月21日學習筆記

MYSQL三層結構 表1 數據庫DB1 表2 數據庫管理系統 客戶端命令終端&#xff08;Dos&#xff09; DBMS 數據庫DB2 表1 表2 數據庫………. Mysql數據庫-表的本質仍然是文件 表的一行稱之為一條記錄->在java程序中一行記錄往往使用對象表示 SQL語…

二十、面向對象底層邏輯-ServiceRegistry接口設計集成注冊中心

一、服務治理的基石接口 在微服務架構中&#xff0c;服務實例的動態注冊與發現是保證系統彈性的關鍵機制。Spring Cloud Commons模塊通過ServiceRegistry與Registration接口定義了服務注冊的標準化模型&#xff0c;為不同服務發現組件&#xff08;Eureka、Consul、Nacos等&…

DeepSeek:以開源之力,引領AI技術新風潮

在年春節&#xff0c;大語言模型DeepSeek如同一枚震撼彈&#xff0c;在全球范圍內引發了轟動&#xff0c;成功“破圈”&#xff0c;將中國的人工智能&#xff08;AI&#xff09;技術成果推向了世界舞臺。 開源策略&#xff1a;打破技術壁壘 在AI行業&#xff0c;OpenAI等巨頭…

完整改進RIME算法,基于修正多項式微分學習算子Rime-ice增長優化器,完整MATLAB代碼獲取

1 簡介 為了有效地利用霧狀冰生長的物理現象&#xff0c;最近開發了一種優化算法——霧狀優化算法&#xff08;RIME&#xff09;。它模擬硬霧狀和軟霧狀過程&#xff0c;構建硬霧狀穿刺和軟霧狀搜索機制。在本研究中&#xff0c;引入了一種增強版本&#xff0c;稱為修改的RIME…

PyTorch可視化工具——使用Visdom進行深度學習可視化

文章目錄 前置環境Visdom安裝并啟動VisdomVisdom圖形APIVisdom靜態更新API詳解通用參數說明使用示例Visdom動態更新API詳解1. 使用updateappend參數2. ~~使用vis.updateTrace方法~~3. 完整訓練監控示例 Visdom可視化操作散點圖plot.scatter()散點圖案例線性圖vis.line()vis.lin…

Java使用Collections集合工具類

1、Collections 集合工具類 Java 中的 Collections 是一個非常有用的工具類&#xff0c;它提供了許多靜態方法來操作或返回集合。這個類位于 java.util 包中&#xff0c;主要包含對集合進行操作的方法&#xff0c;比如排序、搜索、線程安全化等。 Java集合工具類的使用&#x…