• 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

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

    我的 GitHub

    我的 Leetcode

    我的 CSDN

    我的知乎专栏

    我的头条号

    我的牛客网博客

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

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

  • 相关阅读:
    vue3学习(十一)--- v-model
    定向模糊测试aflgo中的能量调度
    Python BeautifulSoup 库使用教程
    你犯过程序员容易犯的这些错误吗?快来看看!
    【优化调度】基于NSGAII算法的车辆充电调度策略研究含Matlab代码
    力扣-58. 最后一个单词的长度
    【MyBatis】MyBatis的前世今生与环境搭建
    盘点8款流行的网红纱帘,以及它们的特点 - 江南爱窗帘十大品牌
    ROS2知识:编译系统ament_cmake
    汽车行业调研:特种车市场发展趋势及现状分析
  • 原文地址:https://blog.csdn.net/zjulyx1993/article/details/133957046