vs
best dp table · best[i] = most cash from houses 0..i · the code keeps only rob1 and rob2
public int rob(int[] nums) { int rob1 = 0; // best up to 2 back int rob2 = 0; // best up to 1 back for (int n : nums) { int temp = Math.max(n + rob1, rob2); // rob vs skip rob1 = rob2; rob2 = temp; } return rob2;}
- n
- —
- rob1
- —
- rob2
- —
- temp
- —
- choice
- —
Why it works
- Brute force tries every set of houses with no two neighbours: about 1.6ⁿ of them, exponential. Greedy fails too: taking every other house misses
[2,1,1,2], where the best (2 + 2) skips two houses in a row. - One choice per house:
best[i] = max(nums[i] + best[i−2], best[i−1]). Rob houseiand you cannot have robbedi−1, so add to the best up toi−2. Skip it and keep the best up toi−1. - Invariant: after each house,
rob2is the best from all houses so far androb1the best without the last one. Only those two are read, so O(n) time and O(1) space. - Pitfall: compute
tempfrom the oldrob1androb2before overwriting either. Androb2does not mean "robbed the previous house": it may have skipped it, which is why themaxnever breaks the no-neighbours rule. - Which houses? Two variables forget the choices. Keep the full table and walk back from the end: if
best[i] ≠ best[i−1], houseiwas robbed, jump toi−2; otherwise step toi−1. - Follow-ups: House Robber II puts the houses in a circle, so run this twice, on
Arrays.copyOfRange(nums, 1, n)andArrays.copyOfRange(nums, 0, n - 1). House Robber III on a tree returns a rob/skip pair per node. Delete and Earn reduces to this problem.