You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. The only constraint stopping you from robbing each of them is that adjacent houses have security systems connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given an integer array nums representing the amount of money in each house, return the
maximum amount of money you can rob tonight without alerting the police.
Example 1:
Input: nums = [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
Total amount you can rob = 2 + 9 + 1 = 12.
Example 2:
Input: nums = [2,1,1,2]
Output: 4
Explanation: Rob house 1 (money = 2) and rob house 4 (money = 2).
Total amount you can rob = 2 + 2 = 4.
Solve Here: Leetcode 198
Intuition
The problem is naturally recursive in nature. For every house, we can either rob it and move to the house two steps ahead, or skip the current house and move to the next house.

Approach 1: Include - Exclude Pattern
Use Recursion to iterate over the houses sequentially. At each index, make a decision to either rob the current house (and skip the next one) or skip the current house and move to the next.
Hypotheses
Let F(currentIndex, nums) be the function that returns the maximum amount of money that can
be robbed from the houses in the range [currentIndex, nums.length-1].
Recursive Steps
// Step 1: Rob the current house and go explore the remaining houses in the range [currentIndex + 2, nums.length-1]
int include = nums[currentIndex] + F(currentIndex + 2, nums);
// Step 2: Ignore the current house and go explore the remaining houses in the range [currentIndex + 1, nums.length-1]
int exclude = F(currentIndex + 1, nums);
// Step 3: Return the maximum amount that can be robbed
return Math.max(include, exclude);
Base Conditions
If no houses are left to be robbed, the maximum amount one can accumulate is 0.
if (currentIndex >= nums.length) {
return 0;
}
Visualization
Time Complexity
Each function branches into two choices. This creates a binary recursion tree whose depth
is proportional to n (the number of houses). Hence, the overall time complexity = O(2^n).
Space Complexity
At each step, the function moves either one step ahead (i + 1) or two steps ahead (i + 2).
The deepest the recursion can go is when we keep taking the i + 1 path, resulting in a maximum
depth of n. Since no additional data structure is used, the overall space complexity = O(n)
due to call stack.
Key Observation
The problem exhibits overlapping subproblems, where we repeatedly compute the maximum amount of money that can be robbed across the same subset of houses.

Approach 2: Memoization
Cache the results of each recursive call in an array to ensure that every subproblem is solved only once. Whenever the same subset of houses are encountred again, reuse the stored result instead of recomputing it.
Hypotheses
Let F(currentIndex, nums, dp) be a function that returns the maximum amount of money that can be robbed
from the houses in the range [currentIndex, nums.length - 1].
Here, dp is a 1-D array of size n, where dp[i] stores the maximum amount that can be robbed starting from index i.
Each cell can be initialized with -1 to indicate that the result for that index has not yet been computed.
int[] dp = new int[n];
Arrays.fill(dp, -1);
Recursive Steps
// Step 1: Rob the current house and go explore the remaining houses in the range [currentIndex + 2, nums.length-1]
int include = nums[currentIndex] + F(currentIndex + 2, nums, dp);
// Step 2: Ignore the current house and go explore the remaining houses in the range [currentIndex + 1, nums.length-1]
int exclude = F(currentIndex + 1, nums, dp);
// Step 3: Return the maximum amount that can be robbed
return dp[currentIndex] = Math.max(include, exclude);
Base Conditions
If no houses are left to be robbed, the maximum amount one can accumulate is 0.
if (currentIndex >= nums.length) {
return 0;
}
If the current subproblem has been computed before, return the result stored in dp.
if (dp[currentIndex] != -1) {
return dp[currentIndex];
}
Visualization
Time Complexity
Since, we only compute each subproblem F(currentIndex, nums, dp) once and the currentIndex only
ranges from 0 to n-1, the overall time complexity = O(n).
Space complexity
We are using a 1-D array of size n to store the results of each subproblem.
The maximum depth the call stack can reach is when we keep taking the i + 1 (exclude) path,
resulting in a maximum depth of n.
Therefore, the overall space complexity = O(n).
Key Observation
The result of each subproblem dp[currentIndex] is dependent on the results of the
dp[currentIndex + 1] and dp[currentIndex + 2] subproblems.

Approach 3: Tabulation
Iterate through the houses from right to left, and at each index, compute the maximum amount of money
that can be robbed from the houses in the range [currentIndex, nums.length - 1] using the formnula:
dp[currentIndex] = Math.max(nums[currentIndex] + dp[currentIndex + 2], dp[currentIndex + 1]).
Algorithm
public int rob(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
for(int i = n - 1; i >= 0; i--) {
int include = i + 2 < n ? nums[i] + dp[i + 2] : nums[i];
int exclude = i + 1 < n ? dp[i + 1] : 0;
dp[i] = Math.max(include, exclude);
}
return dp[0];
}
Visualization
Fill dp[] from right to left. At each index i: dp[i] = max(nums[i] + dp[i+2], dp[i+1])
Time Complexity
Since, we are iterating through the houses from right to left, the overall time complexity = O(n).
Space Complexity
We are using a 1-D array of size n to store the results of each subproblem. Therefore, the overall
space complexity = O(n).
Key Observation
Each subproblem dp[currentIndex] is only dependent on the results of the
dp[currentIndex + 1] and dp[currentIndex + 2] subproblems.
Approach 4: Two Variables
Instead of storing the results of all subproblems in an array, we can use two variables to store the results of the last two subproblems.
Algorithm
public int rob(int[] nums) {
int n = nums.length;
int result = 0;
int next = 0;
int nextToNext = 0;
for(int i = n - 1; i >= 0; i--) {
result = Math.max(nums[i] + nextToNext, next);
nextToNext = next;
next = result;
}
return result;
}
Visualization
Same as tabulation, but only two variables instead of the full array.
next tracks dp[i+1], nextToNext tracks dp[i+2]. Both start at 0.
Time Complexity
Since, we are iterating through the houses from right to left, the overall time complexity = O(n).
Space Complexity
We are using two variables to store the results of the last two subproblems. Therefore, the overall
space complexity = O(1).