LeetCode 之 求根节点到叶节点数字之和

求根节点到叶节点数字之和

题目要求计算根节点到所有叶节点的数字之和,因此需要遍历整个二叉树
涉及二叉树的题目一般考虑用递归解决,涉及路径又可以考虑回溯法(DFS)。
其实递归和回溯不能完全分开,因为递归中往往包含着回溯。

知识点: 递归、回溯法(DFS)
在这里插入图片描述

1. 遍历框架

首先,先来回顾二叉树的遍历框架 ,具体可见我之前的文章 数据结构之树(一)

这里以后序遍历为例,首先需要判断结点是否为空,然后递归左右子树。

void PostOrderTraversal(BinTree BT)
{
	if(BT)	// 为空则返回
	{
		PostOrderTraversal(BT->left);	// 递归左子树,BT->left左子树根节点地址
		PostOrderTraversal(BT->right);	// 递归右子树,BT->right右子树根节点指针
		print("%d", BT->val); 	//访问根节点
	}
}

下面介绍一种更为广义的多叉树遍历框架,来自 labuladong 的算法小抄

void traverse(TreeNode root) {
    for (TreeNode child : root.childern)
        // 前序遍历需要的操作
        traverse(child);
        // 后序遍历需要的操作
}

2. 思路

递归的终止条件:到达叶子结点时,将整条路径的数字加到最后的结果中,并返回
递归函数的作用: 求根节点的左子结点到叶结点的数字之和,求根节点的右子结点到叶结点的数字之和。
递归的参数和返回值:参数为当前路径,用 vector<int> path来表示。回溯法的返回值一般为 void,故此处返回值为 void。此处还需声明全局变量 result 用于保存最终的数字。

3. 实现

下面以递归左子结点为例介绍递归函数的实现。
前序遍历代码:进行递归子节点进行的操作,具体来说就是把左子节点的值加到 path
后序遍历代码:进行递归子节点进行的操作,具体来说就是把左子节点的值从 path 中移除。其实,也是一个回溯的过程,恢复到根节点状态下的 path。

if(root->left)
{
    path.push_back(root->left->val);	# 前序遍历代码
    traverse(root->left, path);	# 递归(遍历)
    path.pop_back();	# 后续遍历代码
}

回溯的过程如下图所示:
递归左结点:路径由 1 变为 12,
回溯:从 12 变为 1;
递归右结点:路径由 1 变为 13,
回溯:从 13 变为 1;
在这里插入图片描述

下面给出具体的代码实现:

法1:详细版
函数 int vectoint(vector<int> path) 将 path 转换为数字

class Solution {
public:
    int result = 0;
    int sumNumbers(TreeNode* root) {
        vector<int> path;
        # 如果根节点为空,返回数字0
        if(root == nullptr) return 0;
        # 向 path 中添加根节点值
        path.push_back(root->val);
        # 调用递归
        traverse(root, path);
        return result;
    }

    int vectoint(vector<int> path)
    {
        int sum = 0;
        for(int i = 0; i < path.size(); i++)
        {
            sum = sum * 10 + path[i];
        }
        return sum;
         
    }

    void traverse(TreeNode* root, vector<int> path)
    {
    # 遇到叶子结点,将结果加入 path 中,返回
        if(!root->left && !root->right)
        {
            result += vectoint(path);
            return;
        }
        if(root->left)
        {
            path.push_back(root->left->val);
            traverse(root->left, path);
            path.pop_back();
        }
        if(root->right)
        {
            path.push_back(root->right->val);
            traverse(root->right, path);
            path.pop_back();
        }
    }
};

法2:简洁版
如果是叶子结点就直接返回结果,如果是非叶子结点就计算子节点数字的和。
pre 是先前路径的数字和,sum 是加入新的结点后的数字和。

class Solution {
public:
    int sumNumbers(TreeNode* root) {
        return traverse(root, 0);
    }
    int traverse(TreeNode* root, int pre)
    {
    # 如果 root 为空就返回 0,避免出现 root->val 访问空指针
        if(root == nullptr) return 0;
        # sum 为当前路径和,在 pre 的基础上加入新的结点值
        int sum = pre * 10 + root->val;
        if(!root->left && !root->right)
        {
        # 叶子结点直接返回
            return sum;
        }
        else
        {
            return traverse(root->left, sum) + traverse(root->right, sum);
        }
    }
};

参考链接

  1. labuladong 的算法小抄
  2. 「代码随想录」129. 求根到叶子节点数字之和【递归中隐藏着回溯】详解
  3. 求根到叶子节点数字之和
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值