算法訓練 | 二叉樹Part5 | 513.找樹左下角的值、112.路徑總和、106.從中序與后序遍歷序列構造二叉樹

目錄

513.找樹左下角的值

遞歸法

迭代法 ?

112.路徑總和

遞歸法

迭代法

106.從中序與后序遍歷序列構造二叉樹

遞歸法


513.找樹左下角的值

  • 題目鏈接:513. 找樹左下角的值 - 力扣(LeetCode)

  • 文章講解:programmercarl.com

遞歸法
  • 解題思路

    • 在樹的最后一行找到最左邊的值。首先要是最后一行,然后是最左邊的值。如果使用遞歸法,如何判斷是最后一行呢,其實就是深度最大的葉子節點一定是最后一行。所以要找深度最大的葉子節點。

    • 那么如何找最左邊的呢?可以使用前序遍歷(當然中序,后序都可以,因為本題沒有 中間節點的處理邏輯,只要左優先就行),保證優先左邊搜索,然后記錄深度最大的葉子節點,此時就是樹的最后一行最左邊的值。

  • 解題步驟

    • 確定遞歸函數的參數和返回值:參數必須有要遍歷的樹的根節點,還有就是一個int型的變量用來記錄最長深度。 這里就不需要返回值了,所以遞歸函數的返回類型為void。本題還需要類里的兩個全局變量,maxLen用來記錄最大深度,result記錄最大深度最左節點的數值。

    • 確定終止條件:當遇到葉子節點的時候,就需要統計一下最大的深度了,所以需要遇到葉子節點來更新最大深度。

    • 確定單層遞歸的邏輯:在找最大深度的時候,遞歸的過程中依然要使用回溯。

  • 代碼一:遞歸

class Solution {
public:int maxDepth = INT_MIN;int result;void traversal(TreeNode* root, int depth) {if (root->left == NULL && root->right == NULL) {if (depth > maxDepth) {maxDepth = depth;result = root->val;}return;}if (root->left) {depth++;traversal(root->left, depth);depth--; // 回溯}if (root->right) {depth++;traversal(root->right, depth);depth--; // 回溯}return;}int findBottomLeftValue(TreeNode* root) {traversal(root, 0);return result;}
};
迭代法 ?
  • 解題思路

    • 只需要記錄最后一行第一個節點的數值就可以了。

  • 代碼一:迭代法

class Solution {
public:int findBottomLeftValue(TreeNode* root) {queue<TreeNode*> que;if (root != NULL) que.push(root);int result = 0;while (!que.empty()) {int size = que.size();for (int i = 0; i < size; i++) {TreeNode* node = que.front();que.pop();if (i == 0) result = node->val; // 記錄最后一行第一個元素if (node->left) que.push(node->left);if (node->right) que.push(node->right);}}return result;}
};

112.路徑總和

  • 題目鏈接:112.路徑總和

  • 文章講解:代碼隨想錄

  • 113.路徑總和ii

遞歸法
  • 解題思路

    • 要遍歷從根節點到葉子節點的路徑看看總和是不是目標和。

    • 可以使用深度優先遍歷的方式(本題前中后序都可以,無所謂,因為中節點也沒有處理邏輯)來遍歷二叉樹

  • 解題步驟

    • 確定遞歸函數的參數和返回類型:

    • 參數:需要二叉樹的根節點,還需要一個計數器,這個計數器用來計算二叉樹的一條邊之和是否正好是目標和,計數器為int型。

    • 返回值,遞歸函數什么時候需要返回值?什么時候不需要返回值?這里總結如下三點,本題并不要遍歷整棵樹,所以遞歸函數需要返回值,可以用bool類型表示。:

      • 如果需要搜索整棵二叉樹且不用處理遞歸返回值,遞歸函數就不要返回值。(113.路徑總和ii)

      • 如果需要搜索整棵二叉樹且需要處理遞歸返回值,遞歸函數就需要返回值。 (二叉樹的最近公共祖先 (opens new window))

      • 如果要搜索其中一條符合條件的路徑,那么遞歸一定需要返回值,因為遇到符合條件的路徑了就要及時返回。(本題的情況)

    • 確定終止條件:首先計數器如何統計這一條路徑的和,不要去累加然后判斷是否等于目標和,代碼比較麻煩,可以用遞減,讓計數器count初始為目標和,然后每次減去遍歷路徑節點上的數值。如果最后count == 0,同時到了葉子節點的話,說明找到了目標和。如果遍歷到了葉子節點,count不為0,就是沒找到。

    • 定單層遞歸的邏輯:因為終止條件是判斷葉子節點,所以遞歸的過程中就不要讓空節點進入遞歸了。遞歸函數是有返回值的,如果遞歸函數返回true,說明找到了合適的路徑,應該立刻返回

  • 代碼一:遞歸

  • class Solution {
    private:bool traversal(TreeNode* cur, int count) {if (!cur->left && !cur->right && count == 0) return true; // 遇到葉子節點,并且計數為0if (!cur->left && !cur->right) return false; // 遇到葉子節點直接返回if (cur->left) { // 左count -= cur->left->val; // 遞歸,處理節點;if (traversal(cur->left, count)) return true;count += cur->left->val; // 回溯,撤銷處理結果}if (cur->right) { // 右count -= cur->right->val; // 遞歸,處理節點;if (traversal(cur->right, count)) return true;count += cur->right->val; // 回溯,撤銷處理結果}return false;}public:bool hasPathSum(TreeNode* root, int sum) {if (root == NULL) return false;return traversal(root, sum - root->val);}
    };
迭代法
  • 解題思路

    • 使用棧模擬遞歸做回溯,此時棧里一個元素不僅要記錄該節點指針,還要記錄從頭結點到該節點的路徑數值總和。c++就我們用pair結構來存放這個棧里的元素。定義為:pair<TreeNode*, int> pair<節點指針,路徑數值>這個為棧里的一個元素。

  • 代碼一:迭代法

class solution {public:bool haspathsum(TreeNode* root, int sum) {if (root == null) return false;// 此時棧里要放的是pair<節點指針,路徑數值>stack<pair<TreeNode*, int>> st;st.push(pair<TreeNode*, int>(root, root->val));while (!st.empty()) {pair<TreeNode*, int> node = st.top();st.pop();// 如果該節點是葉子節點了,同時該節點的路徑數值等于sum,那么就返回trueif (!node.first->left && !node.first->right && sum == node.second) return true;// 右節點,壓進去一個節點的時候,將該節點的路徑數值也記錄下來if (node.first->right) {st.push(pair<TreeNode*, int>(node.first->right, node.second + node.first->right->val));}// 左節點,壓進去一個節點的時候,將該節點的路徑數值也記錄下來if (node.first->left) {st.push(pair<TreeNode*, int>(node.first->left, node.second + node.first->left->val));}}return false;}
};

106.從中序與后序遍歷序列構造二叉樹

  • 題目鏈接:106. 從中序與后序遍歷序列構造二叉樹 - 力扣(LeetCode)

  • 文章講解:代碼隨想錄

  • 105. 從前序與中序遍歷序列構造二叉樹 - 力扣(LeetCode)

遞歸法
  • 解題思路

    • 以后序數組的最后一個元素為切割點,先切中序數組,根據中序數組,反過來再切后序數組。一層一層切下去,每次后序數組最后一個元素就是節點元素。難點是如何切割。應該注意確定切割的標準,是左閉右開,還有左開右閉,還是左閉右閉,這個就是不變量,要在遞歸中保持這個不變量。

    • 首先要切割中序數組,切割點在后序數組的最后一個元素,就是用這個元素來切割中序數組的,所以必要先切割中序數組。中序數組相對比較好切,找到切割點(后序數組的最后一個元素)在中序數組的位置,然后切割。

    • 切割后序數組。首先后序數組的最后一個元素不能要,這是切割點也是當前二叉樹中間節點的元素,已經用了。后序數組沒有明確的切割元素來進行左右切割,不像中序數組有明確的切割點,切割點左右分開就可以了。此時有一個很重的點,就是中序數組大小一定是和后序數組的大小相同的。中序數組都切成了左中序數組和右中序數組了,那么后序數組就可以按照左中序數組的大小來切割,切成左后序數組和右后序數組。

    • 中序數組切成了左中序數組和右中序數組,后序數組切割成左后序數組和右后序數組。接下來可以遞歸。

  • 解題步驟

    • 第一步:如果數組大小為零的話,說明是空節點了。

    • 第二步:如果不為空,那么取后序數組最后一個元素作為節點元素。

    • 第三步:找到后序數組最后一個元素在中序數組的位置,作為切割點

    • 第四步:切割中序數組,切成中序左數組和中序右數組 (順序別反,一定是先切中序數組)

    • 第五步:切割后序數組,切成后序左數組和后序右數組

    • 第六步:遞歸處理左區間和右區間

  • 代碼一:二叉樹構造

class Solution {
private:TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {if (postorder.size() == 0) return NULL;// 后序遍歷數組最后一個元素,就是當前的中間節點int rootValue = postorder[postorder.size() - 1];TreeNode* root = new TreeNode(rootValue);// 葉子節點if (postorder.size() == 1) return root;// 找到中序遍歷的切割點int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 切割中序數組// 左閉右開區間:[0, delimiterIndex)vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);// [delimiterIndex + 1, end)vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end() );// postorder 舍棄末尾元素postorder.resize(postorder.size() - 1);// 切割后序數組// 依然左閉右開,注意這里使用了左中序數組大小作為切割點// [0, leftInorder.size)vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());// [leftInorder.size(), end)vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());root->left = traversal(leftInorder, leftPostorder);root->right = traversal(rightInorder, rightPostorder);return root;}
public:TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {if (inorder.size() == 0 || postorder.size() == 0) return NULL;return traversal(inorder, postorder);}
};

(說明:基于代碼隨想錄課程學習,部分內容引用代碼隨想錄文章)

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

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

相關文章

超聲波清洗機哪些品牌好用點?四大極其出色的機型一目了然

各位眼鏡俠們&#xff0c;在佩戴眼鏡的是&#xff0c;有沒有覺得眼鏡總是有些難以言喻的“味道”或者是污漬在鏡片上面。是的&#xff0c;沒有猜錯&#xff0c;那是我們臉上油脂、汗液和各種不明物質的混合體。特別是在夏天的時候天氣太炎熱會經常出汗&#xff0c;眼鏡上會沾染…

2021職稱繼續教育--加快構建完整內需體系,形成國內國際雙循環相互促進新格局

單選題&#xff08;共7題&#xff0c;每題5分&#xff09; 1、根據本講&#xff0c;突破和推進“一帶一路”戰略&#xff0c;要滿足以企業為主體、以&#xff08;&#xff09;為導向的基本要求。 D、市場 2、根據本講&#xff0c;讓農村消費市場持續擴張的前提&#xff08;&am…

shell將文件分割成小塊文件

背景&#xff1a;某軟件最多支持1G的文件傳輸&#xff0c;需要對大文件進行切割。 方案1&#xff1a; 可以使用split命令將文件均分成10分片。以下是具體的命令示例&#xff1a; split -b $(($(du -b < 文件名) / 10)) 文件名 分片前綴 這里文件名是你想要分割的文件的名…

網絡架構三層到大二層的對比和選擇

在企業的網絡結構選擇中&#xff0c;有二層網絡和三層網絡結構兩種選擇。三層是按照邏輯拓撲結構進行的分類&#xff0c;匯聚層和接入層&#xff0c;流量縱向經過接入層、匯聚層網絡&#xff0c;收斂至骨干核心層。二層網絡結構沒有匯聚層。大二層網絡架構通常使用VLAN&#xf…

上海冠珠旗艦總店盛裝開業暨冠珠瓷磚中國美學設計巡回圓滿舉辦

上海&#xff0c;這座融合了東西方文化的國際化大都市&#xff0c;不僅是中國的時尚中心&#xff0c;也是全球潮流的匯聚地。在這里&#xff0c;古典與現代交織&#xff0c;傳統與前衛并存&#xff0c;為傳統色彩與現代設計的融合提供了得天獨厚的條件。 5月25日&#xff0c;上…

JWT-登錄后下發令牌

后端 寫一個jwt工具類&#xff0c;處理令牌的生成和校驗&#xff0c;如&#xff1a; 響應數據樣例&#xff1a; 前端要做的&#xff1a;

ts 中的 type 和 interface 有什么區別?

一、用法舉例 interface Person {name: stringage: number }const person: Person {name: Kite,age: 24 }type Person {name: stringage: number }const person: Person {name: Kite,age: 24 }二、翻閱 ts 的官方文檔&#xff1a; 1、interface 接口 TypeScript的核心原則…

Weblogic SSRF漏洞 [CVE-2014-4210]

漏洞復現環境搭建請參考 http://t.csdnimg.cn/svKal docker未能成功啟動redis請參考 http://t.csdnimg.cn/5osP3 漏洞原理 Weblogic的uddi組件提供了從其他服務器應用獲取數據的功能并且沒有對目標地址做過濾和限制&#xff0c;造成了SSRF漏洞&#xff0c;利用該漏洞可以向內…

【AJAX前端框架】Asynchronous Javascript And Xml

1 傳統請求及缺點 傳統的請求都有哪些&#xff1f; 直接在瀏覽器地址欄上輸入URL。點擊超鏈接提交form表單使用JS代碼發送請求 window.open(url)document.location.href urlwindow.location.href url… 傳統請求存在的問題 頁面全部刷新導致了用戶的體驗較差。傳統的請求導…

安泰電子:高壓功率放大器應用場合介紹

高壓功率放大器是一種電子設備&#xff0c;用于將低電壓信號放大到較高電壓水平&#xff0c;以滿足各種應用需求。它在多個領域中具有廣泛的應用&#xff0c;包括科學研究、工業生產、通信技術以及醫療設備。下面安泰電子將介紹高壓功率放大器的應用場合。 科學研究 高壓功率放…

【最優化方法】實驗一 熟悉MATLAB基本功能

實驗一  熟悉MATLAB基本功能 實驗的目的和要求&#xff1a;在本次實驗中&#xff0c;通過親臨使用MATLAB&#xff0c;對該軟件做一全面了解并掌握重點內容。 實驗內容&#xff1a; &#xff11;、全面了解MATLAB系統 &#xff12;、實驗常用工具的具體操作和功能 學習建…

在Open AI的Assistant API中,Thread代表什么?

在OpenAI的Assistant API中&#xff0c;Thread通常代表一系列相關的對話&#xff0c;保持對話的上下文和連貫性。這對于創建連續對話非常重要&#xff0c;因為它允許模型記住先前的交互&#xff0c;并在隨后的響應中參考這些信息。 具體作用 保持上下文&#xff1a;Thread可以…

深入學習Python:掌握面向對象編程

在上一篇文章中,我們介紹了Python的基本語法和概念,包括變量、數據類型、條件語句、循環、函數和文件操作。接下來,我們將深入探討Python的面向對象編程(OOP)特性,這是現代編程中的一個重要概念。通過這篇文章,你將學會如何使用類和對象來組織和管理你的代碼。 1. 面向…

哇!數據中臺竟是企業數字化轉型的關鍵力量!

在當今數字化浪潮席卷的時代&#xff0c;數據中臺正成為企業實現數字化轉型的關鍵力量。那么&#xff0c;究竟什么是數據中臺呢&#xff1f;它乃是一種持續讓企業數據活躍起來的機制&#xff0c;能夠將企業內各部分數據匯聚至一個平臺&#xff0c;達成數據的統一化管理。 數據中…

Linux快速定位日志 排查bug技巧和常用命令

1. 快速根據關鍵字定位錯誤信息 grep 在 Linux 系統中&#xff0c;可以使用 grep 命令來查找日志文件中包含特定關鍵字的行。假設你的日志文件路徑為 /var/log/myapp.log&#xff0c;你想要查找包含關鍵字 "abc" 的日志內容&#xff0c;可以按照以下步驟操作&#…

機器學習中的距離公式

1. 歐式距離 (Euclidean Distance) 公式: [ d ( p , q ) = ∑ i = 1 n ( p i ? q i

Intel base instruction -- cmove

Conditional Move&#xff1b;以操作碼&#xff08;條件碼&#xff09;區分不同的移動條件。 opcode 以 0F 4* 打頭&#xff1b; /*509a: eb 0b jmp 50a7 <__sprintf_chkplt0x2937> 509c: 0f 1f 40 00 nopl 0x0(%rax)*/…

TIM(Timer)簡介

TIM&#xff08;Timer&#xff09;定時器介紹 定時器可以對輸入的時鐘進行計數&#xff0c;并在計數值達到設定值時觸發中斷16位計數器、預分頻器、自動重裝寄存器的時基單元&#xff0c;在72MHz計數時鐘下可以實現最大59.65s的定時不僅具備基本的定時中斷功能&#xff0c;而且…

maven的下載以及配置的詳細教程(附網盤下載地址)

文章目錄 下載配置IDEA內部使用配置 下載 1.百度網盤下載 鏈接: https://pan.baidu.com/s/1LD9wOMFalLL49XUscU4qnQ?pwd1234 提取碼: 1234 2.解壓即可 配置 1.打開安裝文件下conf下的settings.xml文件&#xff0c;我的如下 2.修改配置信息&#xff08;目的是為了修改本地…