Skip to content

Coding patternsBlind 75

House Robber

For each house, the best total either skips it or takes it on top of the best from two houses back, so walk the street keeping two numbers. O(n) time and O(1) space, with a step-through, code in five languages and the Big O worked out from the code.

Houses stand in a row, and nums[i] is the money in house i. You may take the money from any houses you like, except that you can never take from two houses next to each other. Return the most money you can take.

Example 1

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

Output: 12

Take houses 0 and 3: 3 + 9 = 12. Taking every other house gives only 3 + 4 = 7 or 1 + 9 = 10.

money
30114293

Example 2

Input: nums = [5]

Output: 5

One house, so take it.

Example 3

Input: nums = [4, 1, 1, 4]

Output: 8

Take the first and the last house. They are not neighbors.

  • 1 ≤ nums.length ≤ 100 (call it n)
  • 0 ≤ nums[i] ≤ 400
Can we skip two or more houses in a row?
Yes. The only rule is never two neighbors. Example 1 skips two houses.
Do the first and last house count as neighbors?
No, the street is a straight line. (House Robber II makes it a circle.)
Can a house hold no money?
Yes, 0 is allowed. No amount is negative, so taking a house never lowers the total by itself.
Do we return the houses or the total?
Just the total.

Look at the last house. Either we skip it, and the answer is the best for the houses before it. Or we take it, so its neighbor is off limits, and the answer is its money plus the best for the houses two back. Each answer comes from answers to smaller streets, and those repeat. That is dynamic programming.

Two numbers O(n)

The table is read only two slots back. So keep just those two answers:

  • two_back: the best total up to two houses ago.
  • one_back: the best total up to the last house.

For each house, the new best is max(one_back, money + two_back). Then slide: two_back takes the old one_back, and one_back takes the new best.

Why it is correct: the two numbers hold exactly the two table slots the rule needs, so it computes the same answers as the table.

money
30114293
two_back
0
one_back
0
  1. two_back, one_back = 0, 0
  2. for money in nums:
  3. take = money + two_back
  4. two_back, one_back = one_back, max(one_back, take)
  5. return one_back

The table only ever reads the two slots behind the one being filled. So keep just two numbers: two_back and one_back, both 0 before any house.

1 / 10
Solution.javasolution.pySolution.cssolution.gosolution.ts
class Solution {
// Two numbers: each answer needs only the two before it, so keep just those
// while walking left to right. O(n) time, O(1) space.
public int rob(int[] nums) {
// Best so far up to two houses back, and up to the last house.
int twoBack = 0, oneBack = 0;
for (int money : nums) {
// Skip this house, or take it on top of the best from two houses back.
int next = Math.max(oneBack, money + twoBack);
twoBack = oneBack;
oneBack = next;
}
return oneBack;
}
}
Time O(n)Space O(1)Here is how we get these from the code, in four steps.
  1. 1 Find the work that repeats

    The loop body does one addition, one max and two moves. That is a fixed job, so each run of the loop counts as 1 step.

    1. two_back, one_back = 0, 0
    2. for money in nums:
    3. take = money + two_back
    4. two_back, one_back = one_back, max(one_back, take)
    5. return one_back
  2. 2 Count the runs on Example 1

    The loop runs once per house.

    4 runs.

    house0123
    loop runs1111
    total
    4 runs
  3. 3 Write the count for any n

    n runs

    Check it with Example 1: n = 4. That matches the count.

  4. 4 Keep only the part that grows fastest

    Nothing to drop. It is O(n).

    So the time is O(n).

  5. S Space: count the extra memory the same way

    Only two_back and one_back are kept, whatever n is. So the space is O(1).

    two_backone_back

2,000 random streets of 1 to 14 houses with amounts 0 to 5, so ties between taking and skipping a house are common. The plain recursion, the table and the two numbers gave the same answer every time.

Largest inputsResult
100 houses (the most allowed), each with up to 400. Two numbers.Under 0.001 s, and under 0.001 MB of extra memory: just the two numbers.
25 houses. Plain recursion.0.02 s. Each extra house makes about 1.6 times more calls, so 100 houses is far out of reach.