DP - 1D· 25 min

House Robber

LeetCode #198 · Medium · Solution walkthrough with Java and Python code

DP - 1D · Medium

LeetCode 198: House Robber — solution

1D DP with a take-or-skip choice at every house: the best total up to house i is the larger of skipping it or robbing it plus the best up to i - 2. O(n) time and O(1) space.

Problem in plain words

Houses stand in a row and each holds some money. You can rob any set of houses as long as no two chosen houses are next to each other (adjacent robberies trigger an alarm). Return the largest total you can collect.

For example, with [5, 1, 1, 5] the best plan robs the first and last houses for 10; robbing the two middle ones is not allowed.

Intuition

At each house you face one decision. Skip it, and your best total is whatever you had after the previous house. Rob it, and you must have skipped the previous house, so you add its money to the best total from two houses back. Taking the larger option at every house gives the optimum, because the best answer for a prefix never depends on anything further right. Like the bottom-up Fibonacci DP lesson, only two earlier values are ever needed.

Approach

  1. State: best[i] is the most money from houses 0..i.
  2. Recurrence: best[i] = max(best[i - 1], best[i - 2] + nums[i]).
  3. Base cases: treat best[-2] = best[-1] = 0, so the first house gives best[0] = nums[0].
  4. Order: left to right, storing the previous two values as prev2 and prev1. The answer is prev1 at the end.

Dry run

Input: nums = [3, 1, 4, 9, 2].

HouseMoneySkip (prev1)Rob (prev2 + money)best
0300 + 3 = 33
1130 + 1 = 13
2433 + 4 = 77
3973 + 9 = 1212
42127 + 2 = 912

The answer is 12, from robbing houses 0 and 3.

Java solution

java
class Solution {
    public int rob(int[] nums) {
        int prev2 = 0, prev1 = 0;   // best up to i-2, best up to i-1
        for (int money : nums) {
            int current = Math.max(prev1, prev2 + money);
            prev2 = prev1;
            prev1 = current;
        }
        return prev1;
    }
}

Python solution

python
class Solution:
    def rob(self, nums: List[int]) -> int:
        prev2, prev1 = 0, 0   # best up to i-2, best up to i-1
        for money in nums:
            prev2, prev1 = prev1, max(prev1, prev2 + money)
        return prev1

Complexity

MeasureCostWhy
TimeO(n)One max per house.
SpaceO(1)Two rolling variables replace the dp array.

Edge cases and common mistakes

  • One house: the loop runs once and returns nums[0].
  • Robbing every other house greedily: picking all even or all odd indices fails on inputs like [2, 1, 1, 9], where the best is 2 + 9 = 11 (indices 0 and 3).
  • Zero-money houses: values can be 0; the max handles them without special cases.
  • Variable update order: compute the new value before shifting prev2 = prev1, or you lose the value from two houses back.
›What changes if the houses are in a circle?

The first and last houses become neighbours. Run this same function twice, once without the last house and once without the first, and take the larger result (that is LeetCode 213).