House Robber
At each house choose the better of robbing it (plus two back) or skipping it.
Animated Rolling DP Trace
Problem
You are given an array where each value is the money available in one house along a street. Choose a set of houses to rob so that no two neighboring houses are chosen, and return the largest total amount you can collect.
Examples
Input: nums = [2, 7, 9, 3, 1]
Output: 12
Input: nums = [5, 1, 1, 5]
Output: 10
The Goal
Each house holds some money. Rob a set of houses, never two next door, and return the largest total.
For [2, 7, 9, 3, 1], robbing the houses with 2, 9 and 1 gives 12.
At every house you choose: skip it, or rob it and give up the house before it.
Two legal choices
Skip house i and keep the best total through i - 1. Or rob it, and add its money to the best total through i - 2.
Key Idea: Skip or Take
Let best(i) be the most you can take from houses 0 through i. Skip house i and you keep best(i - 1). Rob it and house i - 1 is off limits, so you get best(i - 2) + nums[i]:
best(i) = max(best(i - 1), best(i - 2) + nums[i])
At the house with 9, skipping keeps 7 and robbing gives 2 + 9 = 11. Rob it.
Add nums[i] to best(i - 2).
The house next door is left out.
Rolling the DP
The recurrence only looks two houses back, so you don't need the whole table. twoBack and oneBack hold the best totals so far, not house values.
twoBack, oneBack = 0, 0
for money in nums:
current = max(oneBack, twoBack + money)
twoBack, oneBack = oneBack, current
return oneBackCompute current before you shift, or you overwrite a total you still need.
| Approach | Time | Extra space | Trade-off |
|---|---|---|---|
| Full DP array | O(n) | O(n) | Every prefix on show |
| Rolling variables | O(n) | O(1) | Keeps only the two totals needed |
Walkthrough
Run it on [2, 7, 9, 3, 1].
The best totals go 2, 7, 11, 11, 12. At the 3, robbing gives 7 + 3 = 10, less than the 11 you already have, so you skip it. At the 1, robbing gives 11 + 1 = 12.
The answer is 12: houses 0, 2 and 4, holding 2, 9 and 1.
Checkpoint · predict the next step
Step 3 of 7 on the stage: House 1 has 7. Skip it and keep oneBack = 2, or take it: twoBack + 7 = 0 + 7 = 7. Take it: best = 7.
best = [2, 7, ·, ·, ·]
Pitfalls
- Taking every other house fails. For
[5, 1, 1, 5], every other house gives 6 either way, but the first and last give 10. - Grabbing the bigger of two neighbors can block a better pair later.
- Robbing a house adds to
best(i - 2), a total, not tonums[i - 2]. - An empty street gives 0, and one house gives its own value.
What's the most you can take from [5, 1, 1, 5]?
Complexity
Each house gets one addition and one comparison: O(n) time. You keep two totals and a temporary, so extra space is O(1).
Every house has to be read, so no solution beats O(n).
Rolling DP
- Scan each house onceOne recurrence step per house.dominantO(n)
- Compare skip and takeOne addition and one max.O(1)
- Rolling stateTwo totals and a temporary.O(1)
| n | 10 | 100 | 1,000 | 10,000 |
|---|---|---|---|---|
| O(n) | 10 | 100 | 1K | 10K |
As fast as reading the input, in constant memory.
In short
Define best(i) = max(best(i−1), best(i−2) + nums[i]) — skip this house, or take it and whatever was optimal two houses back. Roll two variables forward for O(1) space. The recurrence enforces the no-adjacent constraint automatically.
Common mistake
Greedily taking all even or all odd houses — the optimal choice depends on values, not parity.