House Robber III

MediumTree DP · Post-Order DFS🧩 Tree & Graph DPLeetCode #337 ↗Updated

Problem

Houses form a binary tree; each node holds some money. A thief may rob any set of houses as long as no two robbed houses are directly linked (parent and child). Given the root, return the maximum amount that can be stolen.
Input[3,2,3,null,3,null,1]Output7 (3+3+1)
Input[3,4,5,1,3,null,1]Output9 (4+5)

1 ≤ n ≤ 104  ·  0 ≤ Node.val ≤ 104

Try it yourself

Java
class Solution {
    public int rob(TreeNode root) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
Each node only needs two numbers from each child: the best total if the child is robbed and if it is skipped. Robbing a node forces its children to be skipped; skipping it leaves each child free to take its better option.
PatternTree & Graph DP

Instinct A node's best answer depends only on its children's answers - post-order DFS that returns a tiny tuple of states per node.

Memory hack Kids report up, parent decides - every subtree hands its parent a small report card, and the parent never re-reads the kids' homework.

Open the Tree & Graph DP guide →

Approaches

Brute ForceRob-or-Skip Recursion

Time O(n·φh)Space O(h)

rob(node) = max(val + rob(4 grandchildren), rob(left) + rob(right)). Every node is re-solved from both its parent and its grandparent, so the call count grows like Fibonacci in the depth (φ ≈ 1.618) — exponential on a skewed tree.

Java
public int rob(TreeNode root) {
    if (root == null) return 0;
    int take = root.val;
    if (root.left != null) take += rob(root.left.left) + rob(root.left.right);
    if (root.right != null) take += rob(root.right.left) + rob(root.right.right);
    int skip = rob(root.left) + rob(root.right);
    return Math.max(take, skip);
}

Captures the recurrence, but recomputes the same subtrees exponentially often.

At a glance

LevelApproachTimeSpace
Brute ForceRob-or-Skip RecursionO(n·φh)O(h)
BetterMemoization (HashMap per Node)O(n)O(n)
OptimalPost-Order DP Returning {rob, skip}O(n)O(h)
Common pitfalls
  • Assuming it is “rob alternate levels” — skipping two levels in a row can be optimal.
  • When skipping a node, forcing children to be robbed — each child must take max(rob, skip).
  • Forgetting null checks before reaching grandchildren in the recursive version.
Interview tips
  • Write the take/skip recurrence first; it drives all three versions.
  • Point out the overlap: a grandchild is solved from both its parent and grandparent.
  • Explain why returning a pair removes the need for memoization.
Pattern
Tree DP with per-node states → choose/skip nodes under parent–child constraints (independent set on a tree).
My notes saved in this browser