成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

遞歸函數什么時候要有返回值,什么時候沒有返回值?

開發 前端
相信很多同學都會疑惑,遞歸函數什么時候要有返回值,什么時候沒有返回值,特別是有的時候遞歸函數返回類型為bool類型。

[[417387]]

相信很多同學都會疑惑,遞歸函數什么時候要有返回值,什么時候沒有返回值,特別是有的時候遞歸函數返回類型為bool類型。

那么接下來我通過詳細講解如下兩道題,來回答這個問題:

  • 112.路徑總和
  • 113.路徑總和ii

112. 路徑總和

題目地址:https://leetcode-cn.com/problems/path-sum/

給定一個二叉樹和一個目標和,判斷該樹中是否存在根節點到葉子節點的路徑,這條路徑上所有節點值相加等于目標和。

說明: 葉子節點是指沒有子節點的節點。

示例: 給定如下二叉樹,以及目標和 sum = 22,

返回 true, 因為存在目標和為 22 的根節點到葉子節點的路徑 5->4->11->2。

思路

這道題我們要遍歷從根節點到葉子節點的的路徑看看總和是不是目標和。

遞歸

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

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

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

再來看返回值,遞歸函數什么時候需要返回值?什么時候不需要返回值?這里總結如下三點:

  • 如果需要搜索整顆二叉樹且不用處理遞歸返回值,遞歸函數就不要返回值。(這種情況就是本文下半部分介紹的113.路徑總和ii)
  • 如果需要搜索整顆二叉樹且需要處理遞歸返回值,遞歸函數就需要返回值。(這種情況我們在236. 二叉樹的最近公共祖先介紹)
  • 如果要搜索其中一條符合條件的路徑,那么遞歸一定需要返回值,因為遇到符合條件的路徑了就要及時返回。(本題的情況)

而本題我們要找一條符合條件的路徑,所以遞歸函數需要返回值,及時返回,那么返回類型是什么呢?

如圖所示:

112.路徑總和

圖中可以看出,遍歷的路線,并不要遍歷整棵樹,所以遞歸函數需要返回值,可以用bool類型表示。

所以代碼如下:

  1. bool traversal(treenode* cur, int count) // 注意函數的返回類型 
  • 確定終止條件

首先計數器如何統計這一條路徑的和呢?

不要去累加然后判斷是否等于目標和,那么代碼比較麻煩,可以用遞減,讓計數器count初始為目標和,然后每次減去遍歷路徑節點上的數值。

如果最后count == 0,同時到了葉子節點的話,說明找到了目標和。

如果遍歷到了葉子節點,count不為0,就是沒找到。

遞歸終止條件代碼如下:

  1. if (!cur->left && !cur->right && count == 0) return true; // 遇到葉子節點,并且計數為0 
  2. if (!cur->left && !cur->rightreturn false; // 遇到葉子節點而沒有找到合適的邊,直接返回 
  • 確定單層遞歸的邏輯

因為終止條件是判斷葉子節點,所以遞歸的過程中就不要讓空節點進入遞歸了。

遞歸函數是有返回值的,如果遞歸函數返回true,說明找到了合適的路徑,應該立刻返回。

代碼如下:

  1. if (cur->left) { // 左 (空節點不遍歷) 
  2.     // 遇到葉子節點返回true,則直接返回true 
  3.     if (traversal(cur->leftcount - cur->left->val)) return true; // 注意這里有回溯的邏輯 
  4. if (cur->right) { // 右 (空節點不遍歷) 
  5.     // 遇到葉子節點返回true,則直接返回true 
  6.     if (traversal(cur->rightcount - cur->right->val)) return true; // 注意這里有回溯的邏輯 
  7. return false

以上代碼中是包含著回溯的,沒有回溯,如何后撤重新找另一條路徑呢。

回溯隱藏在traversal(cur->left, count - cur->left->val)這里, 因為把count - cur->left->val 直接作為參數傳進去,函數結束,count的數值沒有改變。

為了把回溯的過程體現出來,可以改為如下代碼:

  1. if (cur->left) { // 左 
  2.     count -= cur->left->val; // 遞歸,處理節點; 
  3.     if (traversal(cur->leftcount)) return true
  4.     count += cur->left->val; // 回溯,撤銷處理結果 
  5. if (cur->right) { // 右 
  6.     count -= cur->right->val; 
  7.     if (traversal(cur->rightcount)) return true
  8.     count += cur->right->val; 
  9. return false

整體代碼如下:

  1. class solution { 
  2. private: 
  3.     bool traversal(treenode* cur, int count) { 
  4.         if (!cur->left && !cur->right && count == 0) return true; // 遇到葉子節點,并且計數為0 
  5.         if (!cur->left && !cur->rightreturn false; // 遇到葉子節點直接返回 
  6.  
  7.         if (cur->left) { // 左 
  8.             count -= cur->left->val; // 遞歸,處理節點; 
  9.             if (traversal(cur->leftcount)) return true
  10.             count += cur->left->val; // 回溯,撤銷處理結果 
  11.         } 
  12.         if (cur->right) { // 右 
  13.             count -= cur->right->val; // 遞歸,處理節點; 
  14.             if (traversal(cur->rightcount)) return true
  15.             count += cur->right->val; // 回溯,撤銷處理結果 
  16.         } 
  17.         return false
  18.     } 
  19.  
  20. public
  21.     bool haspathsum(treenode* root, int sum) { 
  22.         if (root == nullreturn false
  23.         return traversal(root, sum - root->val); 
  24.     } 
  25. }; 

以上代碼精簡之后如下:

  1. class solution { 
  2. public
  3.     bool haspathsum(treenode* root, int sum) { 
  4.         if (root == nullreturn false
  5.         if (!root->left && !root->right && sum == root->val) { 
  6.             return true
  7.         } 
  8.         return haspathsum(root->leftsum - root->val) || haspathsum(root->rightsum - root->val); 
  9.     } 
  10. }; 

是不是發現精簡之后的代碼,已經完全看不出分析的過程了,所以我們要把題目分析清楚之后,在追求代碼精簡。 這一點我已經強調很多次了!

迭代

如果使用棧模擬遞歸的話,那么如果做回溯呢?

此時棧里一個元素不僅要記錄該節點指針,還要記錄從頭結點到該節點的路徑數值總和。

c++就我們用pair結構來存放這個棧里的元素。

定義為:pair

這個為棧里的一個元素。

如下代碼是使用棧模擬的前序遍歷,如下:(詳細注釋)

  1. class solution { 
  2.  
  3. public
  4.     bool haspathsum(treenode* root, int sum) { 
  5.         if (root == nullreturn false
  6.         // 此時棧里要放的是pair<節點指針,路徑數值> 
  7.         stack<pair<treenode*, int>> st; 
  8.         st.push(pair<treenode*, int>(root, root->val)); 
  9.         while (!st.empty()) { 
  10.             pair<treenode*, int> node = st.top(); 
  11.             st.pop(); 
  12.             // 如果該節點是葉子節點了,同時該節點的路徑數值等于sum,那么就返回true 
  13.             if (!node.first->left && !node.first->right && sum == node.secondreturn true
  14.  
  15.             // 右節點,壓進去一個節點的時候,將該節點的路徑數值也記錄下來 
  16.             if (node.first->right) { 
  17.                 st.push(pair<treenode*, int>(node.first->right, node.second + node.first->right->val)); 
  18.             } 
  19.  
  20.             // 左節點,壓進去一個節點的時候,將該節點的路徑數值也記錄下來 
  21.             if (node.first->left) { 
  22.                 st.push(pair<treenode*, int>(node.first->left, node.second + node.first->left->val)); 
  23.             } 
  24.         } 
  25.         return false
  26.     } 
  27. }; 

如果大家完全理解了本地的遞歸方法之后,就可以順便把leetcode上113. 路徑總和ii做了。

113. 路徑總和ii

題目地址:https://leetcode-cn.com/problems/path-sum-ii/

給定一個二叉樹和一個目標和,找到所有從根節點到葉子節點路徑總和等于給定目標和的路徑。

說明: 葉子節點是指沒有子節點的節點。

示例: 給定如下二叉樹,以及目標和 sum = 22,

思路

113.路徑總和ii要遍歷整個樹,找到所有路徑,所以遞歸函數不要返回值!

如圖:

113.路徑總和ii

為了盡可能的把細節體現出來,我寫出如下代碼(這份代碼并不簡潔,但是邏輯非常清晰)

  1. class solution { 
  2. private: 
  3.     vector<vector<int>> result; 
  4.     vector<int> path; 
  5.     // 遞歸函數不需要返回值,因為我們要遍歷整個樹 
  6.     void traversal(treenode* cur, int count) { 
  7.         if (!cur->left && !cur->right && count == 0) { // 遇到了葉子節點且找到了和為sum的路徑 
  8.             result.push_back(path); 
  9.             return
  10.         } 
  11.  
  12.         if (!cur->left && !cur->rightreturn ; // 遇到葉子節點而沒有找到合適的邊,直接返回 
  13.  
  14.         if (cur->left) { // 左 (空節點不遍歷) 
  15.             path.push_back(cur->left->val); 
  16.             count -= cur->left->val; 
  17.             traversal(cur->leftcount);    // 遞歸 
  18.             count += cur->left->val;        // 回溯 
  19.             path.pop_back();                // 回溯 
  20.         } 
  21.         if (cur->right) { // 右 (空節點不遍歷) 
  22.             path.push_back(cur->right->val); 
  23.             count -= cur->right->val; 
  24.             traversal(cur->rightcount);   // 遞歸 
  25.             count += cur->right->val;       // 回溯 
  26.             path.pop_back();                // 回溯 
  27.         } 
  28.         return ; 
  29.     } 
  30.  
  31. public
  32.     vector<vector<int>> pathsum(treenode* root, int sum) { 
  33.         result.clear(); 
  34.         path.clear(); 
  35.         if (root == nullreturn result; 
  36.         path.push_back(root->val); // 把根節點放進路徑 
  37.         traversal(root, sum - root->val); 
  38.         return result; 
  39.     } 
  40. }; 

至于113. 路徑總和ii 的迭代法我并沒有寫,用迭代方式記錄所有路徑比較麻煩,也沒有必要,如果大家感興趣的話,可以再深入研究研究。

總結

本篇通過leetcode上112. 路徑總和 和 113. 路徑總和ii 詳細的講解了 遞歸函數什么時候需要返回值,什么不需要返回值。

這兩道題目是掌握這一知識點非常好的題目,大家看完本篇文章再去做題,就會感受到搜索整棵樹和搜索某一路徑的差別。

對于112. 路徑總和,我依然給出了遞歸法和迭代法,這種題目其實用迭代法會復雜一些,能掌握遞歸方式就夠了!

本文轉載自微信公眾號「代碼隨想錄」,可以通過以下二維碼關注。轉載本文請聯系代碼隨想錄公眾號。

 

責任編輯:武曉燕 來源: 代碼隨想錄
相關推薦

2009-11-17 16:16:59

PHP遞歸函數

2017-06-28 15:06:51

PythonLambda函數

2020-05-12 11:25:50

MySQLES數據庫

2017-05-15 09:55:07

2010-07-21 10:32:05

Perl函數返回值

2015-07-08 15:55:01

NSStringcopystrong

2013-11-28 16:03:24

2012-09-24 10:20:39

JavaScriptJS

2022-05-19 10:27:34

機器學習人工智能

2024-08-05 01:22:16

2009-12-07 11:11:41

WCF返回值

2009-12-25 17:21:13

ADO返回值

2010-07-09 13:20:37

HART協議

2025-01-17 10:52:26

定義函數編程Python

2025-05-15 08:50:00

MQRPC架構

2021-09-29 09:24:21

GCGo STW

2015-10-20 15:59:57

注釋代碼程序

2015-10-26 09:38:52

避免注釋代碼

2020-01-05 23:28:51

MQ消息進程

2021-01-30 19:59:37

性能項目開源
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人三级网址 | 久久久精品久 | 久久久久久国产 | 亚洲欧美精品在线观看 | 久久这里只有精品首页 | 国产污视频在线 | 日韩在线不卡 | 欧美精品在线观看 | 欧美性久久久 | 久久99视频精品 | 国产精品亚洲第一区在线暖暖韩国 | 亚洲www啪成人一区二区 | 日韩在线免费视频 | 久久99蜜桃综合影院免费观看 | 91www在线观看 | 欧美日韩成人网 | 羞羞涩涩在线观看 | 99久久免费精品国产男女高不卡 | 亚洲一级av毛片 | 欧美精品一区在线 | 精品国产一区二区三区久久 | 永久免费在线观看 | 精品福利一区 | 亚洲福利在线观看 | 午夜码电影 | 丁香五月缴情综合网 | 一区二区三区在线免费看 | 国产精品海角社区在线观看 | 日韩中文字幕免费在线 | 中文字幕一级 | 国外成人在线视频 | 国产精品久久国产精品久久 | 97伊人 | 国产在线1| av中文字幕在线播放 | 国产精品国产精品国产专区不片 | 午夜久久久 | 黄色三级毛片 | 日韩电影在线 | www视频在线观看 | 久久无毛 |