Binary Trees · 28 of 35
Find Largest subtree sum in a tree
Find the branch of a tree whose numbers add up to the most, by adding up every branch once from the bottom.
- Simple way
- time O(n^2)
room O(h) - Clever way
- time O(n)
room O(h)
The problem, simply
You get a binary tree of numbers, some of them negative. A subtree is a node together with everything below it. Its sum is all of those numbers added up.
Find the largest subtree sum in the whole tree. The subtree can start at any node, including a single leaf or the root.
A story to remember it
Picture it
The note under each node is its subtree sum. The branch at -2 is worth -2 + 4 + 5 = 7. The branch at 3 is worth only -1. The whole tree is 1 + 7 - 1 = 7.
- answer
Examples
A middle branch wins
- In
[1, -2, 3, 4, 5, -6, 2]- Out
7
The branch at -2 sums to 7. The whole tree also sums to 7. Nothing beats 7.
All negative
- In
[-5, -3, -8]- Out
-3
Every sum is negative. The best is the single leaf -3. Starting the best at 0 would wrongly answer 0.
A deep leaf wins
- In
[-10, 20, -5, null, null, 30, -50]- Out
30
The leaf 30 is worth 30. Its parent -5 adds -50, which drags the bigger branches down.
Everything positive
- In
[1, 2, 3]- Out
6
With no negatives, the whole tree is always the best branch.
One node
- In
[7]- Out
7
The only branch is the root.
Way 1: the simple way
For every node, add up its whole subtree from scratch, and keep the biggest sum.
- Visit every node.
- At each node, walk its whole subtree to get its sum.
- Keep the largest sum seen.
class Solution {
private int best;
public int largestSubtreeSum(TreeNode root) {
if (root == null) return 0;
best = Integer.MIN_VALUE;
visit(root);
return best;
}
private void visit(TreeNode n) {
if (n == null) return;
best = Math.max(best, sum(n)); // add up this whole subtree again
visit(n.left);
visit(n.right);
}
private int sum(TreeNode n) {
if (n == null) return 0;
return n.val + sum(n.left) + sum(n.right);
}
}How long it takes: every node adds up everything below it again. In a stick shaped tree that is about n * n / 2 steps, O(n^2). Extra room: the waiting helpers, O(h).
Way 2: the clever way
Add up each subtree once, from the bottom up. A helper returns its subtree sum to its parent, so the parent never walks down again. Each helper also compares its sum with the best so far.
- An empty spot returns 0.
- Get the left sum
land the right sumr. - This subtree's sum is
node + l + r. Update the best. - Return the sum to the parent.
Sums travel up, the best one is remembered
01 / 09
Each helper returns the sum of its whole subtree. On the way, it compares that sum with the best one seen so far.
- best
- none yet
- looking now
- done
- answer
class Solution {
private int best;
public int largestSubtreeSum(TreeNode root) {
if (root == null) return 0;
best = Integer.MIN_VALUE; // not 0: all sums may be negative
sum(root);
return best;
}
// returns the sum of this subtree and updates best
private int sum(TreeNode n) {
if (n == null) return 0;
int s = n.val + sum(n.left) + sum(n.right);
best = Math.max(best, s);
return s;
}
}How long it takes: each node is visited once, O(n). Extra room: the waiting helpers, O(h).
Watch out for
- Empty subtrees are not branches. An empty side adds 0 to its parent, but 0 is not a candidate answer by itself.
- Mixing this up with maximum path sum. A subtree takes everything below a node. A path picks one route and can skip parts. Here you cannot drop a bad child.
- Big totals can overflow
int. Uselongfor large values.
What interviewers ask next
- Return the root of the best subtree, not just the sum? Save the node whenever
bestchanges. - Most frequent subtree sum? Count each sum in a map during the same walk (LeetCode 508).
- Maximum path sum instead? Return the best downward path (dropping a negative side), and update the answer with
node + left + right(LeetCode 124). - Largest sum of a binary search subtree? Return extra facts per node (is it a search tree, its min, max and sum) and only count valid ones (LeetCode 1373).
Remember this
Grown-up words: the branch is a subtree, its worth is the subtree sum, asking children first is post order traversal, and the best so far is a running maximum.