House Robber
Let dp[i] be the best total for houses 0..i. Then dp[i] = max(dp[i−1], dp[i−2] + nums[i]). Skip house i keeps dp[i−1]. Take house i adds it to dp[i−2]. Each step needs only the two values before it, so two variables are enough.
Taking house i is legal only when we add it to dp[i − 2], because dp[i − 2] never includes house i − 1. Adding it to dp[i − 1] could put two neighbours together.
Problem
A street has a row of houses, and each house holds some money. You want to rob as much as you can, but there is one rule: if you rob two houses that sit next to each other, the alarm goes off.
Return the most money you can take without robbing two neighbouring houses.
nums, a list of whole numbers. nums[i] is the money in house i.
The largest total you can rob, with no two neighbouring houses both robbed.
Rob house 0 (1) and house 2 (3). Total 4. Robbing houses 1 and 2 is not allowed, and robbing houses 1 and 3 gives only 2 + 1 = 3.
Rob houses 0, 2 and 4: 2 + 9 + 1 = 12. No other safe set of houses gives more.
There is only one house, so rob it.
- • 1 ≤ nums.length ≤ 100
- • 0 ≤ nums[i] ≤ 400
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
If I rob house 3, which other houses can I no longer rob?
- 2.
Does the best answer for houses 0 to 4 depend on the best answer for houses 0 to 3, or only on some of the earlier ones?
- 3.
If I know the best answer for the first few houses, what new choice do I have when I look at one more house?
- 4.
What should the answer be when there are no houses at all?
- 5.
Is the answer always the highest-money houses? Try a small row where skipping a big house is the better move.
Brute force approach
Better approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Recurse from the last house: take it (look back 2) or skip it (look back 1) | O(2^N) | O(N) |
| Better | Store each best(i) the first time; later calls return the stored value | O(N) | O(N) |
| Optimal | Keep the last two answers and roll them forward | O(N) | O(1) |
Why does this belong to this pattern?
- “take or skip each house”Each house is a yes or no choice, and the answer depends on the choices made so far.
- “two neighbouring houses cannot both be robbed”A taken house blocks the one before it, so the look-back is 2 steps, not 1.
- “the most money”At each house keep the better of two options. This is a maximum that carries forward.
This is the anchor of the take-or-skip family. At each house the rule is take it and the house before it is out, or skip it. House Robber II changes only the two ends, which touch each other on a ring. Delete and Earn keeps this same rule but applies it to values instead of positions.
Don't make this mistake
Houses with the same parity never touch, so each pile is a safe set. But the best set often mixes both piles. On the dry run [5, 1, 1, 9, 1, 2, 7] the even indices sum to 14 and the odd indices to 12, so the shortcut returns 14. The real answer is 21, from houses 0, 3 and 6 (5 + 9 + 7). Even [2, 1, 1, 2] fails: the shortcut gives 3, but houses 0 and 3 give 4. Only neighbours matter, not index parity.
prev1 is the best up to the previous house, so it may already include house i − 1. On the dry run [5, 1, 1, 9, 1, 2, 7], house 1 gives max(5, 5 + 1) = 6, which robs houses 0 and 1 together. They are neighbours, so that is not allowed.
Sorting by money and grabbing the biggest house fails when a big house blocks two medium ones. On [4, 5, 4] the greedy takes the 5 in the middle and then cannot take either 4, so it gets 5. Robbing both 4s gives 8. The take-or-skip rule has to be checked house by house, in order.
With nums = [5], one loop step leaves prev1 = 5 and prev2 = 0. Returning prev2 gives 0, but the answer is 5. prev1 always holds the latest house.
Want to implement this?
Write it yourself on LeetCode, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like DP — 1D Linear translate into production architectures and low-level memory mechanics.
Foundations: Object-Oriented Principles in C++23
Class invariants, pure virtual interfaces, and RAII smart pointers.
Food Delivery System (Zomato Architecture)
Real-world machine coding application of algorithms and design patterns.
Pointers vs References Deep Dive
Pointer arithmetic and memory layout under the hood.
Virtual Method Table (vtable) & Memory Layout
Polymorphism, vptr overhead, and multiple inheritance in memory.