Leetcode 剑指 Offer II 049. 求根节点到叶节点数字之和

题目难度: 中等

原题链接

今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

给定一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。

每条从根节点到叶节点的路径都代表一个数字:

例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。
计算从根节点到叶节点生成的 所有数字之和 。

叶节点 是指没有子节点的节点。

示例 1:

  • 输入:root = [1,2,3]
  • 输出:25
  • 解释:
    • 从根到叶子节点路径 1->2 代表数字 12
    • 从根到叶子节点路径 1->3 代表数字 13
    • 因此,数字总和 = 12 + 13 = 25

示例 2:

  • 输入:root = [4,9,0,5,1]
  • 输出:1026
  • 解释:
    • 从根到叶子节点路径 4->9->5 代表数字 495
    • 从根到叶子节点路径 4->9->1 代表数字 491
    • 从根到叶子节点路径 4->0 代表数字 40
    • 因此,数字总和 = 495 + 491 + 40 = 1026

提示:

  • 树中节点的数目在范围 [1, 1000] 内
  • 0 <= Node.val <= 9
  • 树的深度不超过 10

题目思考

  1. 如何快速计算每条路径的数字和?

解决方案

思路
  • 分析题目, 要想计算根节点到某个叶子节点的数字和, 我们需要知道该路径的每个节点对应的数字分别是多少, 然后将这些数字拼接起来, 就是当前路径的数字和
  • 根据树的性质, 从根节点到任一节点一定只有唯一一条路径, 所以我们可以保存每一个节点对应路径的所有数字列表, 这样在求根节点到某个叶子的数字和时, 我们只需要在该叶子的父节点的数字列表基础上, 加上该叶子的数字即可
  • 对于这个过程, 我们可以使用自顶向下的 DFS 来解决, 传入当前节点以及对应的根节点->该节点的沿途数字列表, 然后递归调用子节点, 传入子节点以及加上子节点数字的新列表, 直到到达叶子节点, 此时就可以将这些数字拼接起来, 并累加到最终结果里
  • 不过这样我们就得维护当前路径的数字列表, 还得在到达叶子节点后拼接并求和, 有没有更快速的方法呢?
  • 假设有路径1->2->3->4, 其对应的数字自然是 1234, 上面的做法是节点 1 对应数字列表[1], 节点 2 对应数字列表[1,2], 依此类推
  • 我们其实完全没必要保存该列表, 而是可以直接保存数字本身, 然后在调用子节点时, 将该数字乘以 10, 并加上子节点的数字即可
  • 也就是说, 节点 1 对应数字1, 节点 2 对应数字12=1*10+2, 节点 3 对应数字123=12*10+3, 节点 4 对应数字1234=123*10+4, 这样就无需在到达叶子节点后拼接数字了
  • 下面的代码就对应了上面的整个过程, 并且有详细的注释, 方便大家理解
复杂度
  • 时间复杂度 O(N): 每个节点只需要遍历一次
  • 空间复杂度 O(H): H 是树的深度, 也是递归栈的空间消耗
代码
class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        if not root:
            # 根是空节点, 和为0
            return 0
        res = 0

        def dfs(node, num):
            # 传入当前节点node和"根节点->当前节点"的数字num
            nonlocal res
            if not node.left and not node.right:
                # 当前节点是叶子节点, 累加其数字到最终结果
                res += num
                return
            if node.left:
                # 递归调用左子节点, 并更新数字
                dfs(node.left, 10 * num + node.left.val)
            if node.right:
                # 递归调用右子节点, 并更新数字
                dfs(node.right, 10 * num + node.right.val)

        dfs(root, root.val)
        return res

大家可以在下面这些地方找到我~😊

我的 GitHub

我的 Leetcode

我的 CSDN

我的知乎专栏

我的头条号

我的牛客网博客

我的公众号: 算法精选, 欢迎大家扫码关注~😊

算法精选 - 微信扫一扫关注我

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值