Sale: Get 60% Off on all Pro Plans. Buy Now

House Robber III

Medium DFS

Problem

Given the root of a binary tree, return the maximum amount of money the thief can rob without robbing directly connected houses (parent and child nodes).

  • The number of nodes in the tree is in the range [0, 10⁴]
  • 0 ≤ Node.val ≤ 10⁴

Example

Input: root = [3,2,3,null,3,null,1]
Output: 7

The thief can rob the root (3) plus the two grandchildren (3 and 1) for a total of 7. Robbing the root's children (2 and 3) would prevent robbing the root itself, resulting in less total money. The algorithm uses DFS to explore each node's two states: robbing it or skipping it, combining results from children to maximize total profit.

Approach

Straightforward Solution

A naive approach tries all subsets of nodes, checking for adjacency violations, which is exponential and infeasible for large trees.

Core Observation

At each node, the thief faces a binary choice: rob this house and skip its immediate children, or skip this house and consider robbing its children. This creates two states per node that must be tracked and combined to find the global optimum.

Path to Optimal

Preview

The key insight is to use DFS to compute two values for each node: the maximum amount if robbing this node (which excludes its children) and the maximum amount if skipping this node (which allows robbing children)…

Full step-by-step walkthrough on Pro

Optimal Approach

Preview

Implement a DFS helper that returns a tuple (rob_this, skip_this) for each node. 'rob_this' is the node's value plus the 'skip_this' values of its children, ensuring no adjacent nodes are robbed…

Full step-by-step walkthrough on Pro

Want the full reasoning chain?

Unlock the complete walkthrough, line-by-line analysis, and recall drill.

Unlock Pro

Time

O(n)

Each node is visited exactly once in the DFS traversal, and constant work is done per node to compute the two states.

Space

O(h)

The recursion stack depth is proportional to the height of the tree, which is O(h). No additional data structures proportional to n are used.

Pattern Spotlight

DFS (Stateful Exploration with Dual State Tracking)

When a problem requires making mutually exclusive choices at each node (e.g., rob or skip) that affect adjacent nodes, track multiple states per node during DFS to capture all possibilities and combine them optimally.

Solution

Python
1class Solution:
2 def rob(self, root: Optional[TreeNode]) -> int:
3
4 def dfs(node):
5 if not node:
6 return (0, 0)
7
8 left = dfs(node.left)
9 right = dfs(node.right)
10
11 rob_this = node.val + left[1] + right[1]
12
13 skip_this = max(left) + max(right)
14
15 return (rob_this, skip_this)
16
17 return max(dfs(root))

Step-by-Step Solution

1

Recursively Compute Rob and Skip Values for Each Node

4def dfs(node):
5 if not node:
6 return (0, 0)
8 left = dfs(node.left)
9 right = dfs(node.right)
11 rob_this = node.val + left[1] + right[1]
13 skip_this = max(left) + max(right)
15 return (rob_this, skip_this)

Objective

To calculate the maximum money obtainable by either robbing or skipping the current node, based on its children's states.

Key Insight

By returning a tuple of two values from each recursive call—one for robbing the current node and one for skipping it—the algorithm cleanly separates mutually exclusive choices. Robbing the current node adds its value plus the 'skip' values of its children, ensuring no adjacent nodes are robbed. Skipping the current node allows taking the maximum of robbing or skipping each child, maximizing profit without adjacency violations. This dual-state tracking is the core insight that transforms an exponential problem into a linear one.

Interview Quick-Check

Core Logic

The DFS returns two values per node: max profit if robbing this node (node.val + skip values of children) and max profit if skipping this node (max of rob or skip for each child).

State & Boundaries

The base case returns (0, 0) for null nodes, representing zero profit whether robbing or skipping.

Common Pitfalls & Bugs

Failing to separate rob and skip states leads to incorrect sums that violate the adjacency constraint.

Complexity

This approach visits each node once, resulting in O(n) time and O(h) space due to recursion.

2

Return the Maximum Profit from Root Node States

To select the overall maximum profit achievable by either robbing or skipping the root node.

1 more step with full analysis available on Pro.

Line Analysis

This solution has 5 Critical lines interviewers watch for.

Line 11 Critical
rob_this = node.val + left[1] + right[1]

Calculate profit if robbing the current node.

Robbing this node requires skipping its children, so add node's value plus skip values from left and right children to avoid adjacency violations.

Line 13 Critical
skip_this = max(left) + max(right)

Calculate profit if skipping the current node.

Skipping this node allows robbing or skipping children independently, so take the maximum profit from each child's two states and sum them.

Line 5 Critical
if not node:

Check if the current node is null (base case).

Returning (0, 0) for null nodes correctly represents zero profit and terminates recursion safely.

Full line-by-line criticality + rationale for all 9 lines available on Pro.

Test Your Understanding

Why does the algorithm track two values (rob_this and skip_this) for each node instead of a single maximum value?

See the answer with Pro.

Related Problems

DFS pattern

Don't just read it. Drill it.

Reconstruct House Robber III from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the House Robber III drill

or drill a free problem