Skip to content

House Robber

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. Robbers have a constraint: you cannot rob two adjacent houses.

Given an integer array nums representing the amount of money in each house, return the maximum amount of money you can rob without robbing adjacent houses.

numsOutputExplanation
[1, 2, 3, 1]4Rob house 0 (money = 1) and house 2 (money = 3). Total = 1 + 3 = 4
[2, 7, 9, 3, 1]12Rob house 1 (money = 7) and house 3 (money = 3). Total = 7 + 9 = 12
[5, 3, 4, 11, 2]16Rob houses 0, 2, 4. Total = 5 + 4 + 11 = 20… wait, that’s 20. Let me recalculate: houses 0 (5) + 2 (4) + 4 (2) = 11, or 0 (5) + 3 (11) = 16 ✓
  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 400
ApproachTimeSpaceDescription
DP ArrayO(n)O(n)Store all intermediate results for clarity
Space-OptimizedO(n)O(1)Only track the last two values
  • Pick DP Array if you want clarity and ease of debugging.
  • Pick Space-Optimized if you want to show optimization skills and understand the minimal state needed.
Best For Clarity
DP Array
O(n) time · O(n) space
Space Optimized
O(1) Variables
O(n) time · O(1) space
★ Recommended

Create a DP array where dp[i] represents the maximum money you can rob from houses 0 to i.

For each house i, you have two choices:

  • Rob house i: take nums[i] + dp[i-2] (the money from this house plus the max from non-adjacent houses before it)
  • Skip house i: take dp[i-1] (the max from the house before it)

The recurrence is: dp[i] = max(nums[i] + dp[i-2], dp[i-1])

⏱ Time O(n) Single pass 💾 Space O(n) DP array storage

Input: nums = [2, 7, 9, 3, 1]

inums[i]Choice (Rob)Choice (Skip)dp[i]Explanation
02202Rob house 0
17727Rob house 1 (better than house 0)
299 + 2 = 11711Rob house 2 and non-adjacent house 0
333 + 7 = 101111Skip house 3, keep previous max
411 + 11 = 121112Rob house 4 with best from 0-2

Result: Max money = 12 (houses 1 and 3, or houses 0 and 2)

Animated walkthrough

How the DP solution maximizes stolen money

Use Next or Autoplay to watch the maximum money grow as we evaluate each house's rob vs skip decision.

Step 1 of 5 Target: 12
Waiting to begin...
Array state
Memory / lookup state

function houseRobberDpArray(nums):
if nums is empty:
return 0
if nums length is 1:
return nums[0]
dp = array of size len(nums)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i from 2 to len(nums) - 1:
dp[i] = max(nums[i] + dp[i-2], dp[i-1])
return dp[len(nums) - 1]
house_robber_dp_array.py
from typing import List
def house_robber_dp_array(nums: List[int]) -> int:
"""
Rob houses with maximum money using DP array approach.
Time Complexity: O(n)
Space Complexity: O(n)
dp[i] = maximum money robbing houses 0 to i
For each house i, we choose the max of:
- Rob house i + dp[i-2] (skip i-1)
- Don't rob house i + dp[i-1] (keep i-1)
"""
if not nums:
return 0
if len(nums) == 1:
return nums[0]
dp = [0] * len(nums)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, len(nums)):
dp[i] = max(nums[i] + dp[i - 2], dp[i - 1])
return dp[-1]
if __name__ == "__main__":
print(house_robber_dp_array([1, 2, 3, 1])) # 4 (rob house 0 and 2)
print(house_robber_dp_array([2, 7, 9, 3, 1])) # 12 (rob houses 1 and 3)
print(house_robber_dp_array([5, 3, 4, 11, 2])) # 16 (rob houses 0, 2, 4)
🎯 Interview Favourite

Instead of storing the entire DP array, observe that dp[i] only depends on dp[i-1] and dp[i-2]. Therefore, we only need two variables: prev1 (max money up to house i-1) and prev2 (max money up to house i-2).

This approach reduces space complexity from O(n) to O(1) while maintaining the same time complexity.

⏱ Time O(n) Single pass 💾 Space O(1) Only two variables

Input: nums = [2, 7, 9, 3, 1]

inums[i]prev2prev1currentUpdate
Start27Initialize with first two houses
292711max(9+2, 7) = 11, shift: prev2=7, prev1=11
3371111max(3+7, 11) = 11, shift: prev2=11, prev1=11
41111112max(1+11, 11) = 12

Result: Max money = 12

function houseRobberSpaceOptimized(nums):
if nums is empty:
return 0
if nums length is 1:
return nums[0]
prev2 = nums[0]
prev1 = max(nums[0], nums[1])
for i from 2 to len(nums) - 1:
current = max(nums[i] + prev2, prev1)
prev2 = prev1
prev1 = current
return prev1
house_robber_space_optimized.py
from typing import List
def house_robber_space_optimized(nums: List[int]) -> int:
"""
Rob houses with maximum money using space-optimized approach.
Time Complexity: O(n)
Space Complexity: O(1)
We only need the previous two values: prev2 (dp[i-2]) and prev1 (dp[i-1])
To rob house i optimally, we track:
- prev2: max money up to house i-2
- prev1: max money up to house i-1
"""
if not nums:
return 0
if len(nums) == 1:
return nums[0]
prev2 = nums[0] # dp[0]
prev1 = max(nums[0], nums[1]) # dp[1]
for i in range(2, len(nums)):
current = max(nums[i] + prev2, prev1)
prev2 = prev1
prev1 = current
return prev1
if __name__ == "__main__":
print(house_robber_space_optimized([1, 2, 3, 1])) # 4
print(house_robber_space_optimized([2, 7, 9, 3, 1])) # 12
print(house_robber_space_optimized([5, 3, 4, 11, 2])) # 16
✓ Simple

A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.

⏱ Time O(n) Optimized complexity 💾 Space O(1) Efficient space usage
function approach3():
// Implementation approach goes here
house_robber_space_optimized.py
from typing import List
def house_robber_space_optimized(nums: List[int]) -> int:
"""
Rob houses with maximum money using space-optimized approach.
Time Complexity: O(n)
Space Complexity: O(1)
We only need the previous two values: prev2 (dp[i-2]) and prev1 (dp[i-1])
To rob house i optimally, we track:
- prev2: max money up to house i-2
- prev1: max money up to house i-1
"""
if not nums:
return 0
if len(nums) == 1:
return nums[0]
prev2 = nums[0] # dp[0]
prev1 = max(nums[0], nums[1]) # dp[1]
for i in range(2, len(nums)):
current = max(nums[i] + prev2, prev1)
prev2 = prev1
prev1 = current
return prev1
if __name__ == "__main__":
print(house_robber_space_optimized([1, 2, 3, 1])) # 4
print(house_robber_space_optimized([2, 7, 9, 3, 1])) # 12
print(house_robber_space_optimized([5, 3, 4, 11, 2])) # 16