129. Sum Root to Leaf Numbers - Explanation

Problem Link

Description

You are given the root of a binary tree containing digits from 0 to 9 only.

Each root-to-leaf path in the tree represents a number.

  • For example, the root-to-leaf path 1 -> 2 -> 3 represents the number 123.

Return the total sum of all root-to-leaf numbers. Test cases are generated so that the answer will fit in a 32-bit integer.

A leaf node is a node with no children.

Example 1:

Input: root = [1,5,1,null,null,null,6]

Output: 131

Explanation:
The root to leaf path 1 -> 5 represents the number 15.
The root to leaf path 1 -> 1 -> 6 represents the number 116.
The sum of both the numbers is: 15 + 116 = 131.

Example 2:

Input: root = [1,2,1,9,2,3,4]

Output: 478

Explanation:
The root to leaf path 1 -> 2 -> 9 represents the number 129.
The root to leaf path 1 -> 2 -> 2 represents the number 122.
The root to leaf path 1 -> 1 -> 3 represents the number 113.
The root to leaf path 1 -> 1 -> 4 represents the number 114.
The sum the numbers is: 129 + 122 + 113 + 114 = 478.

Constraints:

  • 1 <= number of nodes in the tree <= 1000
  • 0 <= Node.val <= 9
  • The depth of the tree will not exceed 10.


Topics

Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Binary Tree Traversal - Understanding how to navigate through tree nodes using parent-child relationships
  • Depth First Search (DFS) - Recursively exploring paths from root to leaves while maintaining state
  • Path Tracking - Accumulating values along a tree path and recognizing leaf nodes (nodes with no children)

Intuition

Each root-to-leaf path in the tree represents a number, where digits are concatenated from root to leaf. As we traverse down the tree, we build the number by multiplying the accumulated value by 10 and adding the current node's value. When we reach a leaf node, we have a complete number to add to our sum. DFS naturally follows paths from root to leaf, making it ideal for this problem.

Algorithm

  1. Define a recursive dfs function that takes the current node and the accumulated number so far.
  2. If the current node is null, return 0 (base case for empty subtrees).
  3. Update the accumulated number: num = num * 10 + cur.val.
  4. If the current node is a leaf (no children), return the accumulated number.
  5. Otherwise, recursively process both children and return the sum of their results.
  6. Start the dfs from the root with an initial number of 0.
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        def dfs(cur, num):
            if not cur:
                return 0

            num = num * 10 + cur.val
            if not cur.left and not cur.right:
                return num
            return dfs(cur.left, num) + dfs(cur.right, num)

        return dfs(root, 0)

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(h)O(h) for recursion stack.

Where nn is the number of nodes and hh is the height of the given tree.


Intuition

Instead of going deep first, we can process the tree level by level using a queue. Each entry in the queue stores both a node and the number accumulated along the path to reach that node. When we dequeue a leaf node, we add its accumulated number to the total. BFS ensures we visit all nodes while tracking each path's value independently.

Algorithm

  1. Initialize a result variable to 0 and a queue with the root node and initial number 0.
  2. While the queue is not empty:
    • Dequeue a node and its accumulated number.
    • Update the number: num = num * 10 + cur.val.
    • If the node is a leaf, add the number to the result.
    • Otherwise, enqueue each non-null child with the current accumulated number.
  3. Return the total sum.
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        res = 0
        q = deque([(root, 0)])
        while q:
            cur, num = q.popleft()
            num = num * 10 + cur.val
            if not cur.left and not cur.right:
                res += num
                continue

            if cur.left:
                q.append((cur.left, num))
            if cur.right:
                q.append((cur.right, num))

        return res

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

3. Iterative DFS

Intuition

We can simulate the recursive DFS using an explicit stack instead of the call stack. This avoids potential stack overflow for very deep trees. The key insight is to always go left while tracking right children on the stack for later processing. Each stack entry remembers the accumulated number at that point so we can correctly continue building path values.

Algorithm

  1. Initialize result to 0, an empty stack, and start with the root node and number 0.
  2. While the current node exists or the stack is not empty:
    • If current node exists:
      • Update number: num = num * 10 + cur.val.
      • If it is a leaf, add the number to the result.
      • Push the right child and current number onto the stack.
      • Move to the left child.
    • Otherwise, pop from the stack to get the next node and its accumulated number.
  3. Return the result.
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def sumNumbers(self, root: Optional[TreeNode]) -> int:
        res = 0
        stack = []
        cur, num = root, 0

        while cur or stack:
            if cur:
                num = num * 10 + cur.val
                if not cur.left and not cur.right:
                    res += num

                stack.append((cur.right, num))
                cur = cur.left
            else:
                cur, num = stack.pop()

        return res

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(h)O(h)

Where nn is the number of nodes and hh is the height of the given tree.


4. Morris Traversal

Intuition

Morris traversal allows us to traverse the tree without using extra space for a stack or recursion. It temporarily modifies the tree by creating links from predecessors back to their successors. The challenge here is tracking the accumulated number: when we return to a node via a temporary link, we need to "undo" the digits we added while going down the left subtree. We track the number of steps taken to reach the predecessor and divide by the corresponding power of 10 to remove those digits.

Algorithm

  1. Precompute powers of 10 for quick division.
  2. While the current node exists:
    • If no left child exists:
      • Add the current digit to the number.
      • If no right child exists (leaf), add number to result.
      • Move to the right child.
    • Otherwise, find the inorder predecessor (rightmost node in left subtree) while counting steps:
      • If predecessor's right is null, create a temporary link to current, add digit to number, and move left.
      • If predecessor's right points to current (revisiting), remove the link. If predecessor is a leaf, add number to result. Divide number by 10^steps to remove the left subtree digits. Move right.
  3. Return the result.
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def sumNumbers(self, root: Optional[TreeNode]) -> int:
        res = 0
        cur = root
        num = 0
        power = [1] * 10
        for i in range(1, 10):
            power[i] *= power[i - 1] * 10

        while cur:
            if not cur.left:
                num = num * 10 + cur.val
                if not cur.right:
                    res += num
                cur = cur.right
            else:
                prev = cur.left
                steps = 1
                while prev.right and prev.right != cur:
                    prev = prev.right
                    steps += 1

                if not prev.right:
                    prev.right = cur
                    num = num * 10 + cur.val
                    cur = cur.left
                else:
                    prev.right = None
                    if not prev.left:
                        res += num
                    num //= power[steps]
                    cur = cur.right

        return res

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) extra space.

Common Pitfalls

Adding Non-Leaf Node Values to the Sum

A frequent mistake is adding the accumulated number to the result at every node instead of only at leaf nodes. The problem specifically asks for root-to-leaf path numbers, so you must check that both left and right children are null before adding to the sum. Adding at internal nodes will count partial paths and produce incorrect results.

Incorrect Number Accumulation Formula

When building the number along a path, you must multiply the current accumulated value by 10 before adding the new digit: num = num * 10 + node.val. A common error is adding the digit first or forgetting to multiply, which produces single-digit values or incorrect concatenation. Remember that each level represents a new decimal place.

Not Handling Single-Node Trees

When the tree has only a root node with no children, that single node is itself a leaf. Some implementations incorrectly return 0 for this case or fail to recognize it as a valid path. Ensure your base case properly handles when the root exists but has no children, returning just the root's value as the complete number.