House Robber
Introductionβ
The House Robber problem is a popular dynamic programming problem that illustrates how to make optimal decisions while adhering to constraints. In this problem, you must decide how much money to rob from a series of houses lined up in a row, ensuring that no two adjacent houses are robbed to avoid detection.
Exampleβ
Consider the following amounts in houses:
- House values:
[2, 7, 9, 3, 1]
The maximum amount you can rob without alerting the police is 12
, which can be achieved by robbing the houses with values 2
, 9
, and 1
.
Problem Definitionβ
Given an array of non-negative integers representing the amount of money at each house, the objective is to calculate the maximum amount of money you can rob without robbing two adjacent houses.
Dynamic Programming Approachβ
To solve the House Robber problem, we can use dynamic programming by maintaining a dp
array where dp[i]
represents the maximum amount of money that can be robbed up to the i-th house.
Recurrence Relationβ
- For each house
i
, we have two choices:- Rob the current house
i
, adding its value to the maximum amount robbed from houses up toi - 2
: - Skip the current house and take the maximum amount robbed from the previous house:
- Rob the current house
- The state transition is:
Base Caseβ
- If there are no houses, the maximum amount is
0
:dp[0] = 0
. - If there is one house, the maximum amount is its value:
dp[1] = nums[0]
.
Code Implementation in C++β
Hereβs a C++ implementation of the House Robber problem:
#include <iostream>
#include <vector>
using namespace std;
int rob(vector<int>& nums) {
int n = nums.size();
if (n == 0) return 0;
if (n == 1) return nums[0];
// Create a dp array to store the maximum amounts
vector<int> dp(n, 0);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
// Fill the dp array
for (int i = 2; i < n; i++) {
dp[i] = max(dp[i - 1], nums[i] + dp[i - 2]);
}
// The maximum amount is found at dp[n-1]
return dp[n - 1];
}
int main() {
vector<int> houses = {2, 7, 9, 3, 1};
cout << "Maximum amount of money that can be robbed: " << rob(houses) << endl; // Output: 12
// Additional test cases
vector<int> houses1 = {1, 2, 3, 1};
cout << "Maximum amount (1, 2, 3, 1): " << rob(houses1) << endl; // Output: 4
vector<int> houses2 = {2, 1, 1, 2};
cout << "Maximum amount (2, 1, 1, 2): " << rob(houses2) << endl; // Output: 4
return 0;
}
Explanation of the Codeβ
-
Initial Setup:
- We first determine the number of houses
n
and create adp
vector of sizen + 1
, initializing all elements to 0. - The
dp[i]
represents the maximum amount of money that can be robbed up to the i-th house.
- We first determine the number of houses
-
Filling the DP Array:
- We start from the first house and iteratively calculate the maximum money that can be robbed at each house.
- For each house
i
, we have two choices:- Rob the current house and add its value to the maximum amount robbed from houses up to
i - 2
(i.e.,dp[i - 2] + nums[i]
). - Skip the current house and take the maximum amount robbed from the previous house (i.e.,
dp[i - 1]
).
- Rob the current house and add its value to the maximum amount robbed from houses up to
- We take the maximum of these two choices and store it in
dp[i]
.
-
Returning the Result:
- Once the DP array is completely filled, the last element
dp[n]
contains the maximum amount of money that can be robbed from all houses.
- Once the DP array is completely filled, the last element
Time and Space Complexityβ
- Time Complexity: The time complexity is since we iterate through the list of houses once.
- Space Complexity: The space complexity is due to the
dp
array used for storing intermediate results.
Conclusionβ
The House Robber problem is a classic example of dynamic programming that demonstrates how to make optimal decisions at each step to maximize the overall outcome. The approach described here allows for an efficient solution while maintaining clarity and simplicity in code structure.