Skip to content
dsa450for five year olds

Binary Trees · 26 of 35

Sum of Nodes on the Longest path from root to leaf node

Walk every way from the top of a tree to the bottom, and report the total of the longest walk, using the bigger total when two walks are equally long.

Simple way
time O(n * h)
room O(n * h)
Clever way
time O(n)
room O(h)

The problem, simply

Every node of a binary tree holds a number. A root to leaf path starts at the root and goes down until it reaches a node with no children (a leaf).

Find the longest such path, the one with the most nodes, and return the sum of its numbers. If two or more paths are equally long, return the biggest sum among them.

A story to remember it

Picture it

tree
425712363 long3 long3 long4 long

The longest path is 4, 2, 1, 6 with 4 nodes. Every other path has only 3. Its sum is 13.

  • answer
  • path

Examples

One clear winner

In
[4, 2, 5, 7, 1, 2, 3, null, null, 6]
Out
13

4 + 2 + 1 + 6 = 13. It is the only path with 4 nodes, so the sums of the shorter paths do not matter.

A tie on length

In
[1, 2, 3, 4, null, null, 5]
Out
9

Both 1, 2, 4 and 1, 3, 5 have 3 nodes. Their sums are 7 and 9, so the answer is 9.

Only the root

In
[7]
Out
7

The root is also a leaf, so the only path is 7.

Negative numbers

In
[-1, -2, -3, null, -4]
Out
-7

The longest path is -1, -2, -4. Its sum is negative, and that is fine. Do not start the best sum at 0 and keep it there.

Way 1: the simple way

Write down every root to leaf path as its own list. Then go through the lists: find the longest, and among the longest, the biggest sum.

  1. Walk down with a list of the nodes so far. At each leaf, save a copy of the list.
  2. For each saved list, compute its length and sum.
  3. Keep the best by "longer, or same length and bigger sum".
tree
42571236
arraypath to 7
012427
arraypath to 6
01234216
arraypath to 2
012452
arraypath to 3
012453

Four leaves, so four saved lists. Only one has 4 nodes.

  • seen
  • answer
java
import java.util.*;

class Solution {
    public int sumOfLongRootToLeafPath(TreeNode root) {
        if (root == null) return 0;
        List<List<Integer>> paths = new ArrayList<>();
        collect(root, new ArrayList<>(), paths);
        int bestLen = 0, bestSum = Integer.MIN_VALUE;
        for (List<Integer> p : paths) {
            int sum = 0;
            for (int v : p) sum += v;
            if (p.size() > bestLen || (p.size() == bestLen && sum > bestSum)) {
                bestLen = p.size();
                bestSum = sum;
            }
        }
        return bestSum;
    }

    private void collect(TreeNode node, List<Integer> path, List<List<Integer>> paths) {
        if (node == null) return;
        path.add(node.val);
        if (node.left == null && node.right == null) paths.add(new ArrayList<>(path));  // a leaf: save a copy
        collect(node.left, path, paths);
        collect(node.right, path, paths);
        path.remove(path.size() - 1);
    }
}

How long it takes: there can be up to about n / 2 leaves, and each saved copy is up to h long, so O(n * h). Extra room: all those copies, also O(n * h).

Way 2: the clever way

Carry only two numbers down: the length so far and the sum so far. At each leaf, update a best length and best sum. Nothing is copied.

  1. Start at the root with length 0 and sum 0.
  2. At each node, add 1 to the length and the value to the sum.
  3. At a leaf: if the length is bigger than the best length, take this length and sum. If the length is equal and the sum is bigger, take this sum.
  4. Otherwise go into both children with the new numbers.

Carry length and sum down, compare at every leaf

01 / 09

tree
42571236

Start at the root, 4. Length 1, sum 4. Carry both numbers down.

best length
0
best sum
0
  • looking now
  • seen
  • answer
  • path
java
class Solution {
    private int bestLen, bestSum;

    public int sumOfLongRootToLeafPath(TreeNode root) {
        if (root == null) return 0;
        bestLen = 0;
        bestSum = Integer.MIN_VALUE;
        walk(root, 0, 0);
        return bestSum;
    }

    private void walk(TreeNode node, int len, int sum) {
        if (node == null) return;
        len++;
        sum += node.val;
        if (node.left == null && node.right == null) {      // a leaf: compare with the board
            if (len > bestLen || (len == bestLen && sum > bestSum)) {
                bestLen = len;
                bestSum = sum;
            }
            return;
        }
        walk(node.left, len, sum);
        walk(node.right, len, sum);
    }
}

How long it takes: each node once, O(n). Extra room: only the call stack, O(h).

Watch out for

  • Checking at empty children instead of at leaves. A node with one child is not the end of a path; only a node with no children is.
  • Starting the best sum at 0 breaks trees with only negative numbers. Start at the smallest int, or let the first leaf set it because its length beats 0.
  • An empty tree. Decide what to return (usually 0) and handle it before the walk.

What interviewers ask next

  • Return the path itself, not only its sum. Keep the current path in a list and copy it when the best changes, or remember the best leaf and a parent map.
  • The biggest sum of any root to leaf path, ignoring length. Same walk, compare only sums.
  • Can you do it bottom up, without fields? Make each call return a pair (length, sum) of the best path below it, and pick between the left and right pair with the same rule.
  • Do it level by level. With a queue holding (node, sum) pairs, the last row of the tree has the longest paths; take the biggest sum among the leaves of the last row.

Remember this

Grown-up words: the bottom of a slide is a leaf, carrying numbers down while going deep is a preorder depth first search, the board with the best ride is a pair of global variables, and the walk's waiting helpers are the call stack.