house robber problem how to do this this way

Viewed 1258

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 system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Example 1:

  • Input: [1,2,3,1]
  • Output: 4
  • Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). Total amount you can rob = 1 + 3 = 4.

Example 2:

  • Input: [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.
class Solution {
public int rob(int[] nums) {
    int sim=0;
    int sum=0;
    int i,j;

    for(i=0;i<nums.length;i++,i++){
        sim+=nums[i];
    }
    for(j=1;j<nums.length;j++,j++){
        sum+=nums[j];
    }
    int r= Math.max(sim,sum);
    return r;
}
}

How to do this logic when array length is in odd ? can we do that this way output is correct for even length though

3 Answers

Your solution is skipping one house after robbing previous one. This would not always give maximum output. Consider this case: [100, 1, 1, 100]. According to your solution, sim == 101 and sum == 101, however, the correct solution would be 200. (robbing the 0th and 3rd house).

I propose two possible solutions: 1. using recursion, 2. using dp.

Using recursion, you can choose either to rob a house and skip next one, or do not rob a house and go on to the next one. Thus, you will have two recursive cases which would result in O(2^n) time complexity and O(n) space complexity.

public int rob(int[] nums) {
    return robHelper(nums, 0, 0);
}

private int robHelper(int[] nums, int ind, int money) {
    if (ind >= nums.length) return money;

    int rec1 = robHelper(nums, ind+1, money);
    int rec2 = robHelper(nums, ind+2, money+nums[ind]);
    return Math.max(rec1, rec2);
}

Using dp would optimize time and space complexity from above solution. You can keep track of two values: currMax and prevMax. While prevMax is max money excluding the previous house, currMax is max money considering the previous house. Since prevMax is guaranteed that money from previous house is not included, you can add money from current house to prevMax and compare it with currMax to find total max money up to that point. Here is my solution using dp, O(n) time complexity and O(1) space complexity:

public int rob(int[] nums) {
    int currmax = 0;
    int prevmax = 0;

    for (int i = 0; i < nums.length; i++) {
        int iSum = prevmax + nums[i];
        prevmax = currmax;
        currmax = Math.max(currmax, iSum);
    }
    return currmax;
}

As pointed out by siralexsir88 in the comments it is not enough to only check for the solutions for robbing the even/odd numbered houses since it may happen that the best strategy is to skip more than one house in a row.

The given example illustrates this fact: suppose you have [1, 3, 5, 2, 1, 7], here indexes 3 and 4 must be skipped to pick the latter 7.

Proposed solution

This problem is a typical example of dynamic programming and can be solved by building up a solution recursively.

For every house there are two options: you either rob it, our you don't. Let's keep track of the best solution for both cases and for each house: let's name R[i] the maximum profit up to the ith house if we rob the ith house. Let's define NR[i] the same way for not robbing the ith hose.

For example, suppose we have [1, 3]. In this case:

  • R[0] = 1
  • NR[0] = 0
  • R[1] = 3 The best profit while robbing house #1 is 3
  • NR[1] = 1 The best profit while not robbing house #1 is 1

Let's also call P[i] the profit that gives us robbing the ith house. We can build our solution recursively in terms of R and NR this way:

1) R[i] = NR[i-1] + P[i]
2) NR[i] = max(NR[i-1], R[i-1])
3) R[0] = P[0]
4) NR[0] = 0

Let's break it down.

The recursive relation 1) says that if we rob the ith house, we must not have robed the previous house, and hence take the not robbed best score for the previous house.

The recursive relation 2) says that if we do not rob the ith house, then our score is the best between the ones for robbing and not robbing the previous house. This makes sense because we are not adding anything to our total profit, we just keep the best profit so far.

3) and 4) are just the initial conditions for the first house, which should make sense up to this point.

Here is a pseudo-python snippet that does compute the best profit:

P = [1, 3, 5, 2, 1, 7] # The houses
R = [0] * len(P)
NR = [0] * len(P)

R[0] = P[0]

# We skip index 0
for i in range(1, len(P)):
    R[i] = NR[i-1] + P[i]
    NR[i] = max(NR[i-1], R[i-1])

# The solution is the best between NR and R for the last house
print max(NR[-1], R[-1])

The solution implies keeping track of the two arrays (R[i] and NR[i]) while traversing the houses, and then compare the results at the end. If you just want the maximum profit, you may keep the results R and NR for the previous house and ditch them as you move on. However, if you want to know specifically which sequence of houses leads to the best result, you need to keep track of the whole array and once you are done, backtrack and reconstruct the solution.

private static int rob(int[] money) {
    int max = 0;

    for (int i = 0; i < money.length; i++) {
        int skips = 2;

        while (skips < money.length) {
            int sum = 0;

            for (int j = 0; j < money.length; j += skips) {
                sum += money[j];
            }

            if (sum > max) {
                max = sum;
            }
            skips++;
        }
    }

    return max;
}
Related