Today my sister recommended a problem about trees: House Robber III.
The Problem in Brief
We need the maximum path sum from root to leaves of a binary tree, but two adjacent nodes cannot both be taken.
1 | Example 1: |
Solution 1
After reading the problem I came up with a method myself:
Because once a node is taken, its children cannot be counted. So for the current root node there are two cases: “can be taken” or “cannot be taken”.
- For the case where the root node cannot be taken: return the sum of the maxima of its left and right subtrees
- For the case where the root node can be taken: return the maximum of “take the current node” and “don’t take the current node”
The program is as follows:
1 | int robMax(TreeNode* r, bool couldUse) { |
Result
The result was truly tragic:

Solution 2
Because a single function’s return value carries too little information, we have to discuss the takeable and non-takeable cases for every node.
If our function could return a bit more information — also returning the situations of the left and right subtrees — then, thinking this way,
the function returns the maximum of “the root node’s value plus the sums of all subtrees of the left and right subtrees” and “the sum of the maxima of the left and right subtrees”
1 | int robFast(TreeNode* r, int& lMax, int &rMax) { |
Result

Some Runtime Analysis
Take the tree shown below as an example:
1 | 3 |
- Method 1:

From the diagram you can see that from the root node down to the leaves, the time complexity of each level grows in a Fibonacci-sequence manner (I admit my own brain couldn’t see it from the diagram — you can analyze a tree shaped like a singly linked list and find that each level’s complexity is the sum of two Fibonacci numbers).
Below is how a linked-list-shaped tree is computed
1 | 1 t 1t + 0f |
In the Fibonacci sequence: the sum of the first n terms equals the (n+2)th term minus 1. Proof here: Sum of Sequence of Fibonacci Numbers
This should be an exponential-like increase, so producing such a huge runtime — indeed it does.
- Method 2:

Looking back at solution 2, you can see each node is visited once; the time complexity is strictly O(n).
Some Thoughts
When writing recursive functions, we should squeeze every bit of utility out of each function — that is, return every value that can be returned. Perhaps using these return values can effectively reduce the number of recursive calls, thereby improving performance.
In solution 2 above, the maximum values obtainable from the left and right subtrees were also returned, and the function’s performance improved quite a bit.