国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

二叉樹的所有路徑介紹

新材料在線 ? 來源:代碼隨想錄 ? 作者:程序員Carl ? 2021-08-13 17:51 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

以為只用了遞歸,其實(shí)還用了回溯

257. 二叉樹的所有路徑

題目地址:https://leetcode-cn.com/problems/binary-tree-paths/

給定一個二叉樹,返回所有從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的路徑。

說明: 葉子節(jié)點(diǎn)是指沒有子節(jié)點(diǎn)的節(jié)點(diǎn)。

思路

這道題目要求從根節(jié)點(diǎn)到葉子的路徑,所以需要前序遍歷,這樣才方便讓父節(jié)點(diǎn)指向孩子節(jié)點(diǎn),找到對應(yīng)的路徑。

在這道題目中將第一次涉及到回溯,因?yàn)槲覀円崖窂接涗浵聛恚枰厮輥砘赝艘灰粋€路徑在進(jìn)入另一個路徑。

前序遍歷以及回溯的過程如圖:

07b5afe6-fbbe-11eb-9bcf-12bb97331649.png

我們先使用遞歸的方式,來做前序遍歷。要知道遞歸和回溯就是一家的,本題也需要回溯。

遞歸

遞歸函數(shù)函數(shù)參數(shù)以及返回值

要傳入根節(jié)點(diǎn),記錄每一條路徑的path,和存放結(jié)果集的result,這里遞歸不需要返回值,代碼如下:

void traversal(TreeNode* cur, vector《int》& path, vector《string》& result)

確定遞歸終止條件

再寫遞歸的時候都習(xí)慣了這么寫:

if (cur == NULL) {

終止處理邏輯

}

但是本題的終止條件這樣寫會很麻煩,因?yàn)楸绢}要找到葉子節(jié)點(diǎn),就開始結(jié)束的處理邏輯了(把路徑放進(jìn)result里)。

那么什么時候算是找到了葉子節(jié)點(diǎn)? 是當(dāng) cur不為空,其左右孩子都為空的時候,就找到葉子節(jié)點(diǎn)。

所以本題的終止條件是:

if (cur-》left == NULL && cur-》right == NULL) {

終止處理邏輯

}

為什么沒有判斷cur是否為空呢,因?yàn)橄旅娴倪壿嬁梢钥刂瓶展?jié)點(diǎn)不入循環(huán)。

再來看一下終止處理的邏輯。

這里使用vector結(jié)構(gòu)path來記錄路徑,所以要把vector結(jié)構(gòu)的path轉(zhuǎn)為string格式,在把這個string 放進(jìn) result里。

那么為什么使用了vector結(jié)構(gòu)來記錄路徑呢? 因?yàn)樵谙旅嫣幚韱螌舆f歸邏輯的時候,要做回溯,使用vector方便來做回溯。

可能有的同學(xué)問了,我看有些人的代碼也沒有回溯啊。

其實(shí)是有回溯的,只不過隱藏在函數(shù)調(diào)用時的參數(shù)賦值里,下文我還會提到。

這里我們先使用vector結(jié)構(gòu)的path容器來記錄路徑,那么終止處理邏輯如下:

if (cur-》left == NULL && cur-》right == NULL) { // 遇到葉子節(jié)點(diǎn)

string sPath;

for (int i = 0; i 《 path.size() - 1; i++) { // 將path里記錄的路徑轉(zhuǎn)為string格式

sPath += to_string(path[i]);

sPath += “-》”;

}

sPath += to_string(path[path.size() - 1]); // 記錄最后一個節(jié)點(diǎn)(葉子節(jié)點(diǎn))

result.push_back(sPath); // 收集一個路徑

return;

}

確定單層遞歸邏輯

因?yàn)槭乔靶虮闅v,需要先處理中間節(jié)點(diǎn),中間節(jié)點(diǎn)就是我們要記錄路徑上的節(jié)點(diǎn),先放進(jìn)path中。

path.push_back(cur-》val);

然后是遞歸和回溯的過程,上面說過沒有判斷cur是否為空,那么在這里遞歸的時候,如果為空就不進(jìn)行下一層遞歸了。

所以遞歸前要加上判斷語句,下面要遞歸的節(jié)點(diǎn)是否為空,如下

if (cur-》left) {

traversal(cur-》left, path, result);

}

if (cur-》right) {

traversal(cur-》right, path, result);

}

此時還沒完,遞歸完,要做回溯啊,因?yàn)閜ath 不能一直加入節(jié)點(diǎn),它還要刪節(jié)點(diǎn),然后才能加入新的節(jié)點(diǎn)。

那么回溯要怎么回溯呢,一些同學(xué)會這么寫,如下:

if (cur-》left) {

traversal(cur-》left, path, result);

}

if (cur-》right) {

traversal(cur-》right, path, result);

}

path.pop_back();

這個回溯就要很大的問題,我們知道,回溯和遞歸是一一對應(yīng)的,有一個遞歸,就要有一個回溯,這么寫的話相當(dāng)于把遞歸和回溯拆開了, 一個在花括號里,一個在花括號外。

所以回溯要和遞歸永遠(yuǎn)在一起,世界上最遙遠(yuǎn)的距離是你在花括號里,而我在花括號外!

那么代碼應(yīng)該這么寫:

if (cur-》left) {

traversal(cur-》left, path, result);

path.pop_back(); // 回溯

}

if (cur-》right) {

traversal(cur-》right, path, result);

path.pop_back(); // 回溯

}

那么本題整體代碼如下:

class Solution {private:

void traversal(TreeNode* cur, vector《int》& path, vector《string》& result) {

path.push_back(cur-》val);

// 這才到了葉子節(jié)點(diǎn)

if (cur-》left == NULL && cur-》right == NULL) {

string sPath;

for (int i = 0; i 《 path.size() - 1; i++) {

sPath += to_string(path[i]);

sPath += “-》”;

}

sPath += to_string(path[path.size() - 1]);

result.push_back(sPath);

return;

}

if (cur-》left) {

traversal(cur-》left, path, result);

path.pop_back(); // 回溯

}

if (cur-》right) {

traversal(cur-》right, path, result);

path.pop_back(); // 回溯

}

}

public:

vector《string》 binaryTreePaths(TreeNode* root) {

vector《string》 result;

vector《int》 path;

if (root == NULL) return result;

traversal(root, path, result);

return result;

}

};

如上的C++代碼充分體現(xiàn)了回溯。

那么如上代碼可以精簡成如下代碼:

class Solution {private:

void traversal(TreeNode* cur, string path, vector《string》& result) {

path += to_string(cur-》val); // 中

if (cur-》left == NULL && cur-》right == NULL) {

result.push_back(path);

return;

}

if (cur-》left) traversal(cur-》left, path + “-》”, result); // 左

if (cur-》right) traversal(cur-》right, path + “-》”, result); // 右

}

public:

vector《string》 binaryTreePaths(TreeNode* root) {

vector《string》 result;

string path;

if (root == NULL) return result;

traversal(root, path, result);

return result;

}

};

如上代碼精簡了不少,也隱藏了不少東西。

注意在函數(shù)定義的時候void traversal(TreeNode* cur, string path, vector《string》& result) ,定義的是string path,每次都是復(fù)制賦值,不用使用引用,否則就無法做到回溯的效果。

那么在如上代碼中,貌似沒有看到回溯的邏輯,其實(shí)不然,回溯就隱藏在traversal(cur-》left, path + “-》”, result);中的 path + “-》”。 每次函數(shù)調(diào)用完,path依然是沒有加上“-》” 的,這就是回溯了。

為了把這份精簡代碼的回溯過程展現(xiàn)出來,大家可以試一試把:

if (cur-》left) traversal(cur-》left, path + “-》”, result); // 左 回溯就隱藏在這里

改成如下代碼:

path += “-》”;

traversal(cur-》left, path, result); // 左

即:

if (cur-》left) {

path += “-》”;

traversal(cur-》left, path, result); // 左

}

if (cur-》right) {

path += “-》”;

traversal(cur-》right, path, result); // 右

}

此時就沒有回溯了,這個代碼就是通過不了的了。

如果想把回溯加上,就要 在上面代碼的基礎(chǔ)上,加上回溯,就可以AC了。

if (cur-》left) {

path += “-》”;

traversal(cur-》left, path, result); // 左

path.pop_back(); // 回溯

path.pop_back();

}

if (cur-》right) {

path += “-》”;

traversal(cur-》right, path, result); // 右

path.pop_back(); // 回溯

path.pop_back();

}

大家應(yīng)該可以感受出來,如果把 path + “-》”作為函數(shù)參數(shù)就是可以的,因?yàn)椴⒂袥]有改變path的數(shù)值,執(zhí)行完遞歸函數(shù)之后,path依然是之前的數(shù)值(相當(dāng)于回溯了)

綜合以上,第二種遞歸的代碼雖然精簡但把很多重要的點(diǎn)隱藏在了代碼細(xì)節(jié)里,第一種遞歸寫法雖然代碼多一些,但是把每一個邏輯處理都完整的展現(xiàn)了出來了。

迭代法

至于非遞歸的方式,我們可以依然可以使用前序遍歷的迭代方式來模擬遍歷路徑的過程,對該迭代方式不了解的同學(xué),可以看文章二叉樹:聽說遞歸能做的,棧也能做!和二叉樹:前中后序迭代方式統(tǒng)一寫法。

這里除了模擬遞歸需要一個棧,同時還需要一個棧來存放對應(yīng)的遍歷路徑。

C++代碼如下:

class Solution {public:

vector《string》 binaryTreePaths(TreeNode* root) {

stack《TreeNode*》 treeSt;// 保存樹的遍歷節(jié)點(diǎn)

stack《string》 pathSt; // 保存遍歷路徑的節(jié)點(diǎn)

vector《string》 result; // 保存最終路徑集合

if (root == NULL) return result;

treeSt.push(root);

pathSt.push(to_string(root-》val));

while (!treeSt.empty()) {

TreeNode* node = treeSt.top(); treeSt.pop(); // 取出節(jié)點(diǎn) 中

string path = pathSt.top();pathSt.pop(); // 取出該節(jié)點(diǎn)對應(yīng)的路徑

if (node-》left == NULL && node-》right == NULL) { // 遇到葉子節(jié)點(diǎn)

result.push_back(path);

}

if (node-》right) { // 右

treeSt.push(node-》right);

pathSt.push(path + “-》” + to_string(node-》right-》val));

}

if (node-》left) { // 左

treeSt.push(node-》left);

pathSt.push(path + “-》” + to_string(node-》left-》val));

}

}

return result;

}

};

當(dāng)然,使用java的同學(xué),可以直接定義一個成員變量為object的棧Stack《Object》 stack = new Stack《》();,這樣就不用定義兩個棧了,都放到一個棧里就可以了。

總結(jié)

本文我們開始初步涉及到了回溯,很多同學(xué)過了這道題目,可能都不知道自己其實(shí)使用了回溯,回溯和遞歸都是相伴相生的。

我在第一版遞歸代碼中,把遞歸與回溯的細(xì)節(jié)都充分的展現(xiàn)了出來,大家可以自己感受一下。

第二版遞歸代碼對于初學(xué)者其實(shí)非常不友好,代碼看上去簡單,但是隱藏細(xì)節(jié)于無形。

最后我依然給出了迭代法。

對于本地充分了解遞歸與回溯的過程之后,有精力的同學(xué)可以在去實(shí)現(xiàn)迭代法。

其他語言版本

Java:

//解法一class Solution {

/**

* 遞歸法

*/

public List《String》 binaryTreePaths(TreeNode root) {

List《String》 res = new ArrayList《》();

if (root == null) {

return res;

}

List《Integer》 paths = new ArrayList《》();

traversal(root, paths, res);

return res;

}

private void traversal(TreeNode root, List《Integer》 paths, List《String》 res) {

paths.add(root.val);

// 葉子結(jié)點(diǎn)

if (root.left == null && root.right == null) {

// 輸出

StringBuilder sb = new StringBuilder();

for (int i = 0; i 《 paths.size() - 1; i++) {

sb.append(paths.get(i)).append(“-》”);

}

sb.append(paths.get(paths.size() - 1));

res.add(sb.toString());

return;

}

if (root.left != null) {

traversal(root.left, paths, res);

paths.remove(paths.size() - 1);// 回溯

}

if (root.right != null) {

traversal(root.right, paths, res);

paths.remove(paths.size() - 1);// 回溯

}

}

}

Python

class Solution:

def binaryTreePaths(self, root: TreeNode) -》 List[str]:

path=[]

res=[]

def backtrace(root, path):

if not root:return

path.append(root.val)

if (not root.left)and (not root.right):

res.append(path[:])

ways=[]

if root.left:ways.append(root.left)

if root.right:ways.append(root.right)

for way in ways:

backtrace(way,path)

path.pop()

backtrace(root,path)

return [“-》”.join(list(map(str,i))) for i in res]

Go:

func binaryTreePaths(root *TreeNode) []string {

res := make([]string, 0)

var travel func(node *TreeNode, s string)

travel = func(node *TreeNode, s string) {

if node.Left == nil && node.Right == nil {

v := s + strconv.Itoa(node.Val)

res = append(res, v)

return

}

s = s + strconv.Itoa(node.Val) + “-》”

if node.Left != nil {

travel(node.Left, s)

}

if node.Right != nil {

travel(node.Right, s)

}

}

travel(root, “”)

return res

}

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4417

    瀏覽量

    67514
  • 二叉樹
    +關(guān)注

    關(guān)注

    0

    文章

    74

    瀏覽量

    12935

原文標(biāo)題:二叉樹的所有路徑:不止遞歸,還有回溯

文章出處:【微信號:xincailiaozaixian,微信公眾號:新材料在線】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    入門宇機(jī)器人開發(fā):從SDK源碼探索到實(shí)戰(zhàn)操作

    機(jī)器人(Unitree)作為全球領(lǐng)先的四足機(jī)器人研發(fā)企業(yè),其推出的unitree_sdk2是面向旗下 Go2、H1、B2 等系列機(jī)器人的第代軟件開發(fā)工具包。該 SDK 提供了豐富的接口和示例代碼,支持開發(fā)者快速實(shí)現(xiàn)機(jī)器人控制、狀態(tài)獲取、傳感器數(shù)據(jù)處理等功能,是入門宇
    的頭像 發(fā)表于 02-06 16:43 ?2789次閱讀
    入門宇<b class='flag-5'>樹</b>機(jī)器人開發(fā):從SDK源碼探索到實(shí)戰(zhàn)操作

    輸入引腳時鐘約束_Xilinx FPGA編程技巧-常用時序約束詳解

    基本的約束方法 為了保證成功的設(shè)計(jì),所有路徑的時序要求必須能夠讓執(zhí)行工具獲取。最普遍的三種路徑以及異常路徑為: 輸入路徑(Input Path),使用輸入約束 寄存器到寄存器
    發(fā)表于 01-16 08:19

    TüV萊茵與杭集團(tuán)達(dá)成戰(zhàn)略合作并頒發(fā)歐盟CE-MD符合性證書

    日前,國際獨(dú)立第三方檢測、檢驗(yàn)和認(rèn)證機(jī)構(gòu)德國萊茵TüV大中華區(qū)(簡稱"TüV萊茵")與杭集團(tuán)股份有限公司(簡稱"杭集團(tuán)")簽署了戰(zhàn)略合作協(xié)議,標(biāo)志著雙方
    的頭像 發(fā)表于 01-15 12:18 ?281次閱讀

    億緯鋰能與杭集團(tuán)達(dá)成戰(zhàn)略合作

    近日,億緯鋰能與杭集團(tuán)2025年戰(zhàn)略研討會暨戰(zhàn)略合作協(xié)議簽約儀式在杭州舉行。億緯鋰能副總裁、商用車電池產(chǎn)品線總裁江吉兵博士,億緯鋰能商用車電池產(chǎn)品線國內(nèi)銷售部總經(jīng)理井振江,杭集團(tuán)董事、副總經(jīng)理兼
    的頭像 發(fā)表于 01-04 18:18 ?1085次閱讀

    Termux中調(diào)試圣誕Python代碼

    : python --version 如果輸出Python 3.x.x(比如3.11.4),說明安裝成功。 、代碼編寫(兩種方式可選) 方式1:用Termux自帶編輯器(nano)(新手推薦) 創(chuàng)建并編輯
    發(fā)表于 12-09 09:02

    【OK3506-S12Mini試用評測(三)】在虛擬機(jī)中修改設(shè)備

    要實(shí)現(xiàn)引腳復(fù)用功能,核心操作是修改鏡像中的設(shè)備(DTS)文件,具體步驟可按以下詳細(xì)指引操作,確保配置準(zhǔn)確適配開發(fā)板與鏡像版本: 一、定位 DTS 文件路徑 首先需進(jìn)入鏡像對應(yīng)的文件目錄,按以下路徑
    發(fā)表于 11-19 17:21

    通過優(yōu)化代碼來提高M(jìn)CU運(yùn)行效率

    選擇時間復(fù)雜度低的算法。 根據(jù)訪問模式選擇數(shù)據(jù)結(jié)構(gòu)。頻繁查找用哈希表,有序數(shù)據(jù)用二叉樹等。 查表法:對于復(fù)雜的數(shù)學(xué)計(jì)算(如sin, log),或者協(xié)議解析,預(yù)先計(jì)算好結(jié)果存于數(shù)組中,用空間換時間
    發(fā)表于 11-12 08:21

    Verilog實(shí)現(xiàn)使用Booth編碼和Wallace的定點(diǎn)補(bǔ)碼乘法器原理

    的“和”位繼續(xù)在本列傳播,這就構(gòu)成了Wallace Tree乘法器。 Wallace充分利用全加器3-2壓縮的特性,隨時將可利用的所有輸入和中間結(jié)果及時并行計(jì)算,大大節(jié)省了計(jì)算延時。下圖
    發(fā)表于 10-23 08:01

    蜂鳥E203內(nèi)核中斷管理模塊sirv_plic_man代碼分析

    。 上面的代碼生成一個二叉樹結(jié)構(gòu)來比較和選擇具有最大優(yōu)先級的掛起中斷源及其ID。樹狀結(jié)構(gòu)由級聯(lián)比較器組成,每一層的比較器數(shù)量是前一層的一半。在的每一層,選擇優(yōu)先級最高的中斷并傳遞到下一層,直到只剩下
    發(fā)表于 10-23 06:05

    請問rtt studio 的文件夾打紅什么意思?

    rtt studio 的文件夾打紅什么意思?而且文件夾里面實(shí)際是有文件的,但是瀏覽不出來。
    發(fā)表于 09-18 06:34

    科技,被起訴

    電子發(fā)燒友網(wǎng)綜合報(bào)道 天眼查顯示,近日,杭州宇科技股份有限公司(以下簡稱“宇科技”)新增1條開庭公告,原告為杭州露韋美日化有限公司(以下簡稱“露韋美日化”),案由為侵害發(fā)明專利權(quán)糾紛,該案將于8
    的頭像 發(fā)表于 08-26 07:50 ?4930次閱讀
    宇<b class='flag-5'>樹</b>科技,被起訴

    億緯鋰能榮獲杭集團(tuán)2022-2024年度優(yōu)秀供應(yīng)商獎

    近日,億緯鋰能憑借卓越產(chǎn)品、可靠交付與優(yōu)質(zhì)服務(wù)榮獲杭集團(tuán)頒發(fā)的“2022-2024年度優(yōu)秀供應(yīng)商”獎。杭集團(tuán)副總經(jīng)理兼杭電器董事長金華曙、杭電器總經(jīng)理兼杭博電機(jī)總經(jīng)理李明輝出席
    的頭像 發(fā)表于 07-15 09:00 ?986次閱讀

    想在rtsmart中使用uart2,是不是只能通過修改設(shè)備方法來實(shí)現(xiàn)uart2的復(fù)用呀?

    我想在rtsmart中使用uart2,是不是只能通過修改設(shè)備方法來實(shí)現(xiàn)uart2的復(fù)用呀? 修改設(shè)備后如何只編譯設(shè)備文件? 編譯生成的文件可以直接替換到廬山派里嗎,具體替換路徑
    發(fā)表于 06-24 07:04

    電源工程師的核心技能體系

    電源工程師的核心技能體系需覆蓋從基礎(chǔ)理論到專業(yè)實(shí)踐、工具應(yīng)用及行業(yè)適配的全鏈條能力。以下是系統(tǒng)化的技能框架,按知識層級和應(yīng)用場景展開,幫助從業(yè)者明確能力提升路徑: 一、基礎(chǔ)理論層:核心知識根基
    的頭像 發(fā)表于 06-05 09:44 ?2616次閱讀

    白話理解RCC時鐘(可下載)

    時鐘就像是單片機(jī)的“心臟”,單片機(jī)正常工作離不開時鐘的支持,下圖是我們單片機(jī)的時鐘 ,它反映了單片機(jī)的時鐘關(guān)系。我們來詳細(xì)描述一下時鐘的工作原理。寄存器上電后有一個復(fù)位值,大家看我畫紅線的這個
    發(fā)表于 03-27 13:50 ?0次下載