消除左递归c++代码_「leetcode」129. 求根到叶子节点数字之和【递归中隐藏着回溯】详解...
鏈接
https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/
思路
本題和113.路徑總和II是類似的思路,做完這道題,可以順便把113.路徑總和II 和 112.路徑總和 做了。
結(jié)合112.路徑總和 和 113.路徑總和II,我在講了二叉樹(shù):遞歸函數(shù)究竟什么時(shí)候需要返回值,什么時(shí)候不要返回值?,如果大家對(duì)二叉樹(shù)遞歸函數(shù)什么時(shí)候需要返回值很迷茫,可以看一下。
接下來(lái)在看本題,就簡(jiǎn)單多了,本題其實(shí)需要使用回溯,但一些同學(xué)可能都不知道自己用了回溯,在二叉樹(shù):以為使用了遞歸,其實(shí)還隱藏著回溯中,我詳細(xì)講解了二叉樹(shù)的遞歸中,如何使用了回溯。
接下來(lái)我們來(lái)看題:
首先思路很明確,就是要遍歷整個(gè)樹(shù)把更節(jié)點(diǎn)到葉子節(jié)點(diǎn)組成的數(shù)字相加。
那么先按遞歸三部曲來(lái)分析:
遞歸三部曲
如果對(duì)遞歸三部曲不了解的話,可以看這里:二叉樹(shù):前中后遞歸詳解
- 確定遞歸函數(shù)返回值及其參數(shù)
這里我們要遍歷整個(gè)二叉樹(shù),且需要要返回值做邏輯處理,所有返回值為void,在二叉樹(shù):遞歸函數(shù)究竟什么時(shí)候需要返回值,什么時(shí)候不要返回值?中,詳細(xì)講解了返回值問(wèn)題。
參數(shù)只需要把根節(jié)點(diǎn)傳入,此時(shí)還需要定義兩個(gè)全局遍歷,一個(gè)是result,記錄最終結(jié)果,一個(gè)是vector path。
「為什么用vector類型(就是數(shù)組)呢? 因?yàn)橛胿ector方便我們做回溯!」
所以代碼如下:
int result; vector<int> path; void traversal(TreeNode* cur)- 確定終止條件
遞歸什么時(shí)候終止呢?
當(dāng)然是遇到葉子節(jié)點(diǎn),此時(shí)要收集結(jié)果了,通知返回本層遞歸,因?yàn)閱螚l路徑的結(jié)果使用vector,我們需要一個(gè)函數(shù)vectorToInt把vector轉(zhuǎn)成int。
終止條件代碼如下:
if (!cur->left && !cur->right) { // 遇到了葉子節(jié)點(diǎn)result += vectorToInt(path);return; }這里vectorToInt函數(shù)就是把數(shù)組轉(zhuǎn)成int,代碼如下:
int vectorToInt(const vector<int>& vec) {int sum = 0;for (int i = 0; i < vec.size(); i++) {sum = sum * 10 + vec[i];}return sum; }- 確定遞歸單層邏輯
本題其實(shí)采用前中后序都不無(wú)所謂, 因?yàn)橐矝](méi)有中間幾點(diǎn)的處理邏輯。
這里主要是當(dāng)左節(jié)點(diǎn)不為空,path收集路徑,并遞歸左孩子,右節(jié)點(diǎn)同理。
「但別忘了回溯」。
如圖:
代碼如下:
// 中 if (cur->left) { // 左 (空節(jié)點(diǎn)不遍歷)path.push_back(cur->left->val);traversal(cur->left); // 遞歸path.pop_back(); // 回溯 } if (cur->right) { // 右 (空節(jié)點(diǎn)不遍歷)path.push_back(cur->right->val);traversal(cur->right); // 遞歸path.pop_back(); // 回溯 }這里要注意回溯和遞歸要永遠(yuǎn)在一起,一個(gè)遞歸,對(duì)應(yīng)一個(gè)回溯,是一對(duì)一的關(guān)系,有的同學(xué)寫成如下代碼:
if (cur->left) { // 左 (空節(jié)點(diǎn)不遍歷)path.push_back(cur->left->val);traversal(cur->left); // 遞歸 } if (cur->right) { // 右 (空節(jié)點(diǎn)不遍歷)path.push_back(cur->right->val);traversal(cur->right); // 遞歸 } path.pop_back(); // 回溯「把回溯放在花括號(hào)外面了,世界上最遙遠(yuǎn)的距離,是你在花括號(hào)里,而我在花括號(hào)外!」 這就不對(duì)了。
整體C++代碼
關(guān)鍵邏輯分析完了,整體C++代碼如下:
class Solution { private:int result;vector<int> path;// 把vector轉(zhuǎn)化為intint vectorToInt(const vector<int>& vec) {int sum = 0;for (int i = 0; i < vec.size(); i++) {sum = sum * 10 + vec[i];}return sum;}void traversal(TreeNode* cur) {if (!cur->left && !cur->right) { // 遇到了葉子節(jié)點(diǎn)result += vectorToInt(path);return;}if (cur->left) { // 左 (空節(jié)點(diǎn)不遍歷)path.push_back(cur->left->val);traversal(cur->left); // 遞歸path.pop_back(); // 回溯}if (cur->right) { // 右 (空節(jié)點(diǎn)不遍歷)path.push_back(cur->right->val);traversal(cur->right); // 遞歸path.pop_back(); // 回溯}return ;} public:int sumNumbers(TreeNode* root) {path.clear();if (root == nullptr) return 0;path.push_back(root->val);traversal(root);return result;} };總結(jié)
過(guò)于簡(jiǎn)潔的代碼,很容易讓初學(xué)者忽視了本題中回溯的精髓,甚至作者本身都沒(méi)有想清楚自己用了回溯。
我這里提供的代碼把整個(gè)回溯過(guò)程充分的提現(xiàn)出來(lái),希望可以幫助大家看的明明白白!
本文:
https://github.com/youngyangyang04/leetcode-master?github.com已經(jīng)收錄,里面還有l(wèi)eetcode刷題攻略、各個(gè)類型經(jīng)典題目刷題順序、思維導(dǎo)圖,可以fork到自己倉(cāng)庫(kù),有空看一看一定會(huì)有所收獲,如果對(duì)你有幫助也給一個(gè)star支持一下吧! 我的B站(里面有我講解的算法視頻已經(jīng)編程相關(guān)知識(shí)):
嗶哩嗶哩 ( ゜- ゜)つロ 乾杯~ Bilibili?space.bilibili.com我是程序員Carl,哈工大師兄,先后在騰訊和百度從事技術(shù)研發(fā)多年,利用工作之余重刷leetcode,更多精彩算法文章盡在:代碼隨想錄,關(guān)注后,回復(fù)「Java」「C++」「python」「簡(jiǎn)歷模板」等等,有我整理多年的學(xué)習(xí)資料,可以加我微信,備注「?jìng)€(gè)人簡(jiǎn)介」+「組隊(duì)刷題」,拉你進(jìn)入刷題群,每天一道經(jīng)典題目分析,我選的每一道題目都不是孤立的,而是由淺入深一脈相承的,如果跟住節(jié)奏每篇連續(xù)著看,定會(huì)融會(huì)貫通。
總結(jié)
以上是生活随笔為你收集整理的消除左递归c++代码_「leetcode」129. 求根到叶子节点数字之和【递归中隐藏着回溯】详解...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 交行信用卡年费 交通银行的信用卡年费是多
- 下一篇: cvc降噪和主动降噪_市面上的降噪耳机,