House Robber (original) (raw)

Given an array **arr[] where each element shows the amount of money in a row of houses built in a line. A robber wants to steal money, but cannot rob two houses adjacent to each other because it will set off an alarm.
Find the **maximum money the robber can steal without robbing two adjacent houses.

**Examples:

**Input: arr[] = [6, 7, 1, 3, 8, 2, 4]
**Output: 19
**Explanation: The thief will steal from house 1, 3, 5 and 7, total money = 6 + 1 + 8 + 4 = 19.

**Input: arr[] = [5, 3, 4, 11, 2]
**Output: 16
**Explanation: Thief will steal from house 1 and 4, total money = 5 + 11 = 16.

Table of Content

[Naive Approach] Using Recursion- O(2^n) Time and O(n) Space

The idea is to explore all the possibilities for each house using Recursion. We can start from the last house and for each house, we have two choices:

  1. Rob the current house and skip the house just before it.
  2. Skip the current house and move to the next house.

Recursion-Tree-for-House-Robber

C++ `

//Driver Code Starts #include #include using namespace std; //Driver Code Ends

// Calculate the maximum stolen value recursively int findMaxSumRec(vector &arr, int n) {

// If no houses are left, return 0.
if (n <= 0)  return 0;

  // If only 1 house is left, rob it. 
if (n == 1)  return arr[0];

// Two Choices: Rob the nth house and do not rob the nth house 
int pick = arr[n - 1] + findMaxSumRec(arr, n - 2);
int notPick = findMaxSumRec(arr, n - 1);

// Return the max of two choices
return max(pick, notPick);

}

// Function to calculate the maximum stolen value int findMaxSum(vector&arr) { int n = arr.size();

// Call the recursive function for n houses
  return findMaxSumRec(arr, n);

}

//Driver Code Starts int main() { vector arr = {6, 7, 1, 3, 8, 2, 4}; cout << findMaxSum(arr); return 0; }

//Driver Code Ends

C

//Driver Code Starts #include <stdio.h> //Driver Code Ends

// Calculate the maximum stolen value recursively int findMaxSumRec(int arr[], int n) {

// If no houses are left, return 0.
if (n <= 0)  return 0;

  // If only 1 house is left, rob it. 
if (n == 1)  return arr[0];

// Two Choices: Rob the nth house and do not rob the nth house 
int pick = arr[n - 1] + findMaxSumRec(arr, n - 2);
int notPick = findMaxSumRec(arr, n - 1);

// Return the max of two choices
return (pick > notPick) ? pick : notPick;

}

// Function to calculate the maximum stolen value int findMaxSum(int arr[], int n) {

// Call the recursive function for n houses
  return findMaxSumRec(arr, n);

}

//Driver Code Starts int main() { int arr[] = {6, 7, 1, 3, 8, 2, 4}; int n = sizeof(arr) / sizeof(arr[0]); printf("%d", findMaxSum(arr, n)); return 0; }

//Driver Code Ends

Java

//Driver Code Starts

class GFG { //Driver Code Ends

// Calculate the maximum stolen value recursively
static int findMaxSumRec(int[] arr, int n) {
    
    // If no houses are left, return 0.
    if (n <= 0)  return 0;
  
    // If only 1 house is left, rob it. 
    if (n == 1)  return arr[0];

    // Two Choices: Rob the nth house and do not rob the nth house 
    int pick = arr[n - 1] + findMaxSumRec(arr, n - 2);
    int notPick = findMaxSumRec(arr, n - 1);

    // Return the max of two choices
    return Math.max(pick, notPick);
}

// Function to calculate the maximum stolen value
static int findMaxSum(int[] arr) {
    int n = arr.length;
    
    // Call the recursive function for n houses
    return findMaxSumRec(arr, n);
}

//Driver Code Starts public static void main(String[] args) { int[] arr = {6, 7, 1, 3, 8, 2, 4}; System.out.println(findMaxSum(arr)); } }

//Driver Code Ends

Python

Calculate the maximum stolen value recursively

def findMaxSumRec(arr, n):

# If no houses are left, return 0.
if n <= 0:
    return 0

  # If only 1 house is left, rob it. 
if n == 1:
    return arr[0]

# Two Choices: Rob the nth house and do not rob the nth house 
pick = arr[n - 1] + findMaxSumRec(arr, n - 2)
notPick = findMaxSumRec(arr, n - 1)

# Return the max of two choices
return max(pick, notPick)

Function to calculate the maximum stolen value

def findMaxSum(arr): n = len(arr)

# Call the recursive function for n houses
return findMaxSumRec(arr, n)

if name == "main": #Driver Code Starts arr = [6, 7, 1, 3, 8, 2, 4] print(findMaxSum(arr))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

// Calculate the maximum stolen value recursively
static int findMaxSumRec(int[] arr, int n) {

    // If no houses are left, return 0.
    if (n <= 0)  return 0;

      // If only 1 house is left, rob it. 
    if (n == 1)  return arr[0];

    // Two Choices: Rob the nth house and do not rob the nth house 
    int pick = arr[n - 1] + findMaxSumRec(arr, n - 2);
    int notPick = findMaxSumRec(arr, n - 1);

    // Return the max of two choices
    return Math.Max(pick, notPick);
}

// Function to calculate the maximum stolen value
static int findMaxSum(int[] arr) {
    int n = arr.Length;
    
    // Call the recursive function for n houses
      return findMaxSumRec(arr, n);
}

//Driver Code Starts static void Main() { int[] arr = {6, 7, 1, 3, 8, 2, 4}; Console.WriteLine(findMaxSum(arr)); } }

//Driver Code Ends

JavaScript

// Calculate the maximum stolen value recursively function findMaxSumRec(arr, n) {

// If no houses are left, return 0.
if (n <= 0)  return 0;

  // If only 1 house is left, rob it. 
if (n === 1)  return arr[0];

// Two Choices: Rob the nth house and do not rob the nth house 
let pick = arr[n - 1] + findMaxSumRec(arr, n - 2);
let notPick = findMaxSumRec(arr, n - 1);

// Return the max of two choices
return Math.max(pick, notPick);

}

// Function to calculate the maximum stolen value function findMaxSum(arr) { let n = arr.length;

// Call the recursive function for n houses
  return findMaxSumRec(arr, n);

}

let arr = [6, 7, 1, 3, 8, 2, 4]; //Driver Code Starts console.log(findMaxSum(arr));

//Driver Code Ends

`

[Better Approach] Using Memoization - O(n) Time and O(n) Space

In the recursive approach, many subproblems are solved multiple times because the same states are revisited again and again - this leads to overlapping subproblems and increases the time complexity.

We can optimize the recursive solution by using a memoization array of size (n + 1). Here, memo[i] represents the maximum amount of money that can be stolen from the first i houses.

In the recursive approach, only one parameter - the number of houses changes during each recursive call. Since the range of this parameter is from 0 to n, we can store and reuse previously computed results for each state to avoid redundant calculations.

C++ `

//Driver Code Starts #include #include using namespace std; //Driver Code Ends

int findMaxSumRec( vector& arr, int n, vector& memo) {

if (n <= 0) return 0;
if (n == 1) return arr[0];

// Check if the result is already computed
if (memo[n] != -1) return memo[n];

int pick = arr[n - 1] + findMaxSumRec(arr, n - 2, memo);
int notPick = findMaxSumRec(arr, n - 1, memo);

// Store the max of two choices in the memo array and return it
memo[n] = max(pick, notPick);
return memo[n];

}

int findMaxSum(vector& arr) { int n = arr.size();

// Initialize memo array with -1
vector<int> memo(n + 1, -1); 
return findMaxSumRec(arr, n, memo);

}

//Driver Code Starts int main() { vectorarr = {6, 7, 1, 3, 8, 2, 4}; cout << findMaxSum(arr); return 0; }

//Driver Code Ends

C

//Driver Code Starts #include <stdio.h> //Driver Code Ends

// Calculate the maximum stolen value recursively with memoization int findMaxSumRec(int arr[], int n, int memo[]) {

if (n <= 0) return 0;
if (n == 1) return arr[0];

// Check if the result is already computed
if (memo[n] != -1) return memo[n];

int pick = arr[n - 1] + findMaxSumRec(arr, n - 2, memo);
int notPick = findMaxSumRec(arr, n - 1, memo);

// Store the max of two choices in the memo array and return it
memo[n] = (pick > notPick) ? pick : notPick;
return memo[n];

}

int findMaxSum(int arr[], int n) {

// Initialize memo array with -1
int memo[n + 1];
for (int i = 0; i <= n; i++) memo[i] = -1;

return findMaxSumRec(arr, n, memo);

}

//Driver Code Starts int main() { int arr[] = {6, 7, 1, 3, 8, 2, 4}; int n = sizeof(arr)/sizeof(arr[0]); printf("%d", findMaxSum(arr, n)); return 0; }

//Driver Code Ends

Java

//Driver Code Starts import java.util.Arrays;

class GFG { //Driver Code Ends

static int findMaxSumRec(int[] arr, int n, int[] memo) {

    if (n <= 0) return 0;
    if (n == 1) return arr[0];

    // Check if the result is already computed
    if (memo[n] != -1) return memo[n];

    int pick = arr[n - 1] + findMaxSumRec(arr, n - 2, memo);
    int notPick = findMaxSumRec(arr, n - 1, memo);

    // Store the max of two choices in the memo array and return it
    memo[n] = Math.max(pick, notPick);
    return memo[n];
}

static int findMaxSum(int[] arr) {
    int n = arr.length;

    // Initialize memo array with -1
    int[] memo = new int[n + 1];
    Arrays.fill(memo, -1);
    return findMaxSumRec(arr, n, memo);
}

//Driver Code Starts public static void main(String[] args) { int[] arr = {6, 7, 1, 3, 8, 2, 4}; System.out.println(findMaxSum(arr)); } }

//Driver Code Ends

Python

Calculate the maximum stolen value recursively with memoization

def findMaxSumRec(arr, n, memo):

if n <= 0:
    return 0
if n == 1:
    return arr[0]

# Check if the result is already computed
if memo[n] != -1:
    return memo[n]

pick = arr[n - 1] + findMaxSumRec(arr, n - 2, memo)
notPick = findMaxSumRec(arr, n - 1, memo)

# Store the max of two choices in the memo array and return it
memo[n] = max(pick, notPick)
return memo[n]

Function to calculate the maximum stolen value

def findMaxSum(arr): n = len(arr)

# Initialize memo array with -1
memo = [-1] * (n + 1)
return findMaxSumRec(arr, n, memo)

#Driver Code Starts if name == "main": arr = [6, 7, 1, 3, 8, 2, 4] print(findMaxSum(arr))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

static int findMaxSumRec(int[] arr, int n, int[] memo) {

    if (n <= 0) return 0;
    if (n == 1) return arr[0];

    // Check if the result is already computed
    if (memo[n] != -1) return memo[n];

    int pick = arr[n - 1] + findMaxSumRec(arr, n - 2, memo);
    int notPick = findMaxSumRec(arr, n - 1, memo);

    // Store the max of two choices in the memo array and return it
    memo[n] = Math.Max(pick, notPick);
    return memo[n];
}

static int findMaxSum(int[] arr) {
    int n = arr.Length;

    // Initialize memo array with -1
    int[] memo = new int[n + 1];
    for (int i = 0; i <= n; i++) memo[i] = -1;
    return findMaxSumRec(arr, n, memo);
}

//Driver Code Starts static void Main() { int[] arr = {6, 7, 1, 3, 8, 2, 4}; Console.WriteLine(findMaxSum(arr)); } }

//Driver Code Ends

JavaScript

function findMaxSumRec(arr, n, memo) {

if (n <= 0) return 0;
if (n === 1) return arr[0];

// Check if the result is already computed
if (memo[n] !== -1) return memo[n];

let pick = arr[n - 1] + findMaxSumRec(arr, n - 2, memo);
let notPick = findMaxSumRec(arr, n - 1, memo);

// Store the max of two choices in the memo array and return it
memo[n] = Math.max(pick, notPick);
return memo[n];

}

function findMaxSum(arr) { let n = arr.length;

// Initialize memo array with -1
let memo = new Array(n + 1).fill(-1);
return findMaxSumRec(arr, n, memo);

}

//Driver Code //Driver Code Starts let arr = [6, 7, 1, 3, 8, 2, 4]; console.log(findMaxSum(arr));

//Driver Code Ends

`

[Expected Approach 1] Using Tabulation - O(n) Time and O(n) Space

In this approach, we build the solution iteratively from the ground up, starting with the smallest subproblems. We first define the base cases, and then gradually compute the answers for larger problems using the results of previously solved smaller ones.

Here, we create a dp[] array where dp[i] represents the maximum amount of money that can be stolen from the first i houses.

Initially,

Then, we iterate through the remaining houses and fill the dp[] array using this formula:

//Driver Code Starts #include #include using namespace std; //Driver Code Ends

int findMaxSum(vector& arr) { int n = arr.size();

// Create a dp array to store the maximum loot at each house
vector<int> dp(n+1, 0);

// Base cases
dp[0] = 0;
dp[1] = arr[0];

// Fill the dp array using the bottom-up approach
for (int i = 2; i <= n; i++) 
    dp[i] = max(arr[i - 1] + dp[i - 2], dp[i - 1]);

return dp[n];

}

//Driver Code Starts int main() { vectorarr = {6, 7, 1, 3, 8, 2, 4}; cout << findMaxSum(arr) << endl; return 0; } //Driver Code Ends

C

//Driver Code Starts #include <stdio.h> //Driver Code Ends

// Function to calculate the maximum stolen value int findMaxSum(int arr[], int n) {

// Create a dp array to store the maximum loot at each house
int dp[n + 1];

// Base cases
dp[0] = 0;
dp[1] = arr[0];

// Fill the dp array using the bottom-up approach
for (int i = 2; i <= n; i++) 
    dp[i] = (arr[i - 1] + dp[i - 2] > dp[i - 1]) ? 
             (arr[i - 1] + dp[i - 2]) : dp[i - 1];

return dp[n];

}

//Driver Code Starts int main() { int arr[] = {6, 7, 1, 3, 8, 2, 4}; int n = sizeof(arr) / sizeof(arr[0]); printf("%d ", findMaxSum(arr, n)); return 0; }

//Driver Code Ends

Java

//Driver Code Starts

class GFG { //Driver Code Ends

static int findMaxSum(int[] arr) {
    int n = arr.length;

    // Create a dp array to store the maximum loot at each house
    int[] dp = new int[n + 1];

    // Base cases
    dp[0] = 0;
    dp[1] = arr[0];

    // Fill the dp array using the bottom-up approach
    for (int i = 2; i <= n; i++)
        dp[i] = Math.max(arr[i - 1] + dp[i - 2], dp[i - 1]);

    return dp[n];
}

//Driver Code Starts public static void main(String[] args) { int[] arr = {6, 7, 1, 3, 8, 2, 4}; System.out.println(findMaxSum(arr)); } }

//Driver Code Ends

Python

def findMaxSum(arr): n = len(arr)

# Create a dp array to store the maximum loot at each house
dp = [0] * (n + 1)

# Base cases
dp[0] = 0
dp[1] = arr[0]

# Fill the dp array using the bottom-up approach
for i in range(2, n + 1):
    dp[i] = max(arr[i - 1] + dp[i - 2], dp[i - 1])

return dp[n]

if name == "main": #Driver Code Starts arr = [6, 7, 1, 3, 8, 2, 4] print(findMaxSum(arr))

#Driver Code Ends

C#

//Driver Code Starts using System; //Driver Code Ends

class GFG {

static int findMaxSum(int[] arr) {
    int n = arr.Length;

    // Create a dp array to store the maximum loot at each house
    int[] dp = new int[n + 1];

    // Base cases
    dp[0] = 0;
    dp[1] = arr[0];

    // Fill the dp array using the bottom-up approach
    for (int i = 2; i <= n; i++)
        dp[i] = Math.Max(arr[i - 1] + dp[i - 2], dp[i - 1]);

    return dp[n];
}

//Driver Code Starts static void Main() { int[] arr = {6, 7, 1, 3, 8, 2, 4}; Console.WriteLine(findMaxSum(arr)); } }

//Driver Code Ends

JavaScript

function findMaxSum(arr) { let n = arr.length;

// Create a dp array to store the maximum loot at each house
let dp = new Array(n + 1).fill(0);

// Base cases
dp[0] = 0;
dp[1] = arr[0];

// Fill the dp array using the bottom-up approach
for (let i = 2; i <= n; i++) 
    dp[i] = Math.max(arr[i - 1] + dp[i - 2], dp[i - 1]);

return dp[n];

}

//Driver Code //Driver Code Starts let arr = [6, 7, 1, 3, 8, 2, 4]; console.log(findMaxSum(arr));

//Driver Code Ends

`

[Expected Approach 2] Space-Optimized DP - O(n) Time and O(1) Space

On observing the dp[] array in the previous approach, it can be seen that the answer at the current index depends only on the last two values. In other words, dp[i] depends only on dp[i - 1] and dp[i - 2]. So, instead of storing the result in an array, we can simply use two variables to store the last and second last result.

C++ `

//Driver Code Starts #include #include using namespace std; //Driver Code Ends

int findMaxSum(vector &arr) { int n = arr.size();

if (n == 0)
    return 0;
if (n == 1)
    return arr[0];

// Set previous 2 values
int secondLast = 0, last = arr[0];

// Compute current value using previous two values
// The final current value would be our result
int res;
for (int i = 1; i < n; i++) {
    res = max(arr[i] + secondLast, last);
    secondLast = last;
    last = res;
}
return res;

}

//Driver Code Starts int main() { vector arr = {6, 7, 1, 3, 8, 2, 4}; cout << findMaxSum(arr) << endl; return 0; } //Driver Code Ends

C

//Driver Code Starts #include <stdio.h> //Driver Code Ends

int findMaxSum(int arr[], int n) {

if (n == 0)
    return 0;
if (n == 1)
    return arr[0];

// Set previous 2 values
int secondLast = 0, last = arr[0];

// Compute current value using previous two values
// The final current value would be our result
int res;
for (int i = 1; i < n; i++) {
    res = (arr[i] + secondLast > last) ? (arr[i] + secondLast) : last;
    secondLast = last;
    last = res;
}
return res;

}

//Driver Code Starts int main() { int arr[] = {6, 7, 1, 3, 8, 2, 4}; int n = sizeof(arr) / sizeof(arr[0]); printf("%d ", findMaxSum(arr, n)); return 0; }

//Driver Code Ends

Java

//Driver Code Starts class GFG { //Driver Code Ends

static int findMaxSum(int[] arr) {
    int n = arr.length;

    if (n == 0)
        return 0;
    if (n == 1)
        return arr[0];

    // Set previous 2 values
    int secondLast = 0, last = arr[0];

    // Compute current value using previous two values
    // The final current value would be our result
    int res = 0;
    for (int i = 1; i < n; i++) {
        res = Math.max(arr[i] + secondLast, last);
        secondLast = last;
        last = res;
    }
    return res;
}

//Driver Code Starts public static void main(String[] args) { int[] arr = {6, 7, 1, 3, 8, 2, 4}; System.out.println(findMaxSum(arr)); } }

//Driver Code Ends

Python

def findMaxSum(arr): n = len(arr)

if n == 0:
    return 0
if n == 1:
    return arr[0]

# Set previous 2 values
secondLast, last = 0, arr[0]

# Compute current value using previous two values
# The final current value would be our result
for i in range(1, n):
    res = max(arr[i] + secondLast, last)
    secondLast = last
    last = res
return res

if name == "main": #Driver Code Starts arr = [6, 7, 1, 3, 8, 2, 4] print(findMaxSum(arr))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

static int findMaxSum(int[] arr) {
    int n = arr.Length;

    if (n == 0)
        return 0;
    if (n == 1)
        return arr[0];

    // Set previous 2 values
    int secondLast = 0, last = arr[0];

    // Compute current value using previous two values
    // The final current value would be our result
    int res = 0;
    for (int i = 1; i < n; i++) {
        res = Math.Max(arr[i] + secondLast, last);
        secondLast = last;
        last = res;
    }
    return res;
}

//Driver Code Starts static void Main() { int[] arr = {6, 7, 1, 3, 8, 2, 4}; Console.WriteLine(findMaxSum(arr)); } }

//Driver Code Ends

JavaScript

function findMaxSum(arr) { let n = arr.length;

if (n === 0)
    return 0;
if (n === 1)
    return arr[0];

// Set previous 2 values
let secondLast = 0, last = arr[0];

// Compute current value using previous two values
// The final current value would be our result
let res;
for (let i = 1; i < n; i++) {
    res = Math.max(arr[i] + secondLast, last);
    secondLast = last;
    last = res;
}
return res;

}

//Driver Code //Driver Code Starts let arr = [6, 7, 1, 3, 8, 2, 4]; console.log(findMaxSum(arr));

//Driver Code Ends

`