House Robber Solution
Given an array of non-negative integers representing money in each house, return the maximum amount you can rob without robbing two adjacent houses.
Problem Statement
You are a professional robber. Each house has a certain amount of money stashed. Adjacent houses have connected security systems โ robbing two neighbors triggers an alarm. Return the maximum amount you can rob tonight.
Recursion โ O(2โฟ)
For each house, decide: rob it (skip neighbor, add value) or skip it. Recursively compute both choices and take the max. This explores every possible combination.
The recursion correctly tries all valid subsets โ no two adjacent houses robbed. The maximum across all valid subsets is the answer.
rob(i) is called multiple times for the same i. Total calls: O(2โฟ). Memoization or bottom-up DP reduces this to O(n) by storing each subproblem result once.
| Metric | Value |
|---|---|
| Time | O(2โฟ) |
| Space | O(n) call stack |
Two-Variable DP โ O(n) time, O(1) space
At each house, the best choice is max(skip this house = prev best, rob this house = prev-prev best + this house). Since we only look back two steps, two variables suffice.
prev1= best total including or excluding the previous house.prev2= best total as of two houses ago.- For each house:
cur = max(prev1, prev2 + nums[i]). Then shift:prev2 = prev1; prev1 = cur. - Return
prev1.
- "Can't pick adjacent elements, maximize/minimize sum." The signal is a take/skip decision at each index with a constraint linking adjacent choices.
- Variations: LC 213 (circular), LC 740 (Delete and Earn โ reduce to House Robber via frequency array), LC 746 (Min Cost Climbing Stairs).
- The "rob this house" option needs the best excluding the previous house โ that's
prev2. - If you only tracked one variable, you'd lose the information about what was optimal two steps back after overwriting it.
Visual Walkthrough
Trace for nums = [2, 7, 9, 3, 1].
Code โ Java & Python
Complexity Analysis
| Approach | Time | Space | Trade-off |
|---|---|---|---|
| Naive recursion | O(2โฟ) | O(n) | Exponential โ TLE for n > 30 |
| Memoized recursion / DP array | O(n) | O(n) | Correct but uses extra dp[] array |
| Two-variable DP โ optimal | O(n) | O(1) | Constant space; minimal code |
Edge Cases & Pitfalls
| Case | Input | Why It Matters |
|---|---|---|
| Single house | [5] | Rob it. prev1=5 after one iteration. |
| Two houses | [1,2] | Rob the richer one. max(1,2)=2. |
| All zeros | [0,0,0] | Max is 0. Algorithm handles naturally. |
| All equal | [5,5,5,5] | Rob alternating: 5+5=10. |
| Descending | [10,5,3,1] | Rob [10,3]=13 vs [5,1]=6. prev2+nums[i] wins early. |
| Large values | 100 houses ร 400 each | Max possible: 50ร400=20,000 โ fits int easily. |
prev1 = nums[0] and prev2 = 0 then starting the loop at i=1. This works but requires a guard for empty arrays. The cleaner pattern โ start both at 0 and loop from the beginning โ handles all edge cases uniformly without special-casing nums.length == 1.