Sword finger offer89: House theft

Posted by zipp on Fri, 11 Feb 2022 15:53:42 +0100

Title:
A professional thief plans to steal houses along the street. There is a certain amount of cash hidden in each room. The only restrictive factor affecting the thief's theft is that the adjacent houses are equipped with interconnected anti-theft systems. If two adjacent houses are intruded by thieves on the same night, the system will automatically alarm.
Given a non negative integer array nums representing the amount stored in each house, please calculate the maximum amount that can be stolen overnight without touching the alarm device.
Example 1:
Input: num = [1,2,3,1]
Output: 4
Explanation: steal house 1 (amount = 1) and then steal house 3 (amount = 3).
Maximum amount stolen = 1 + 3 = 4.
Example 2:
Input: num = [2,7,9,3,1]
Output: 12
Explanation: steal house 1 (amount = 2), steal house 3 (amount = 9), and then steal house 5 (amount = 1).
Maximum amount stolen = 2 + 9 + 1 = 12.
analysis:
Because this problem does not require the thief to list all the theft methods that meet the conditions, but only to find the maximum financial quantity that can be stolen, that is, to find the optimal solution of the problem, this problem is suitable for the use of dynamic programming.
The key of applying dynamic programming to solve the problem is to find out the state transition equation. Suppose there are n houses on the street (labeled with 0~n-1 respectively). F (I) represents the maximum financial value that the thief can steal from the house labeled 0 to the house labeled I. The value of F (n-1) is the maximum amount of property that the thief can steal from n houses, This is the solution to the problem. The thief has two choices in front of the house labeled I. one choice is that he goes in and steals. Due to the alarm system on the street, he cannot enter the adjacent house marked I-1 to steal. Before, the maximum financial value he can steal is f (i-2). Therefore, if a thief enters the house marked I to steal, the maximum financial value he can steal is f (i-2) + nums[i]. Another option is that the thief does not enter the house marked I, Then he can enter the house labeled I-1 to steal, so the maximum amount of Finance he can steal is f (i-1) Then when the thief reaches the house labeled I, the maximum financial value he can steal is the maximum value of the two options, that is, f (I) = max (f (i-2) + nums[i],f(i-1)).
The above state transition equation has an implicit condition, assuming that i is greater than or equal to 2 When i is equal to 0, f (0) is the maximum amount of finance that a thief can steal when there is only one house with label 0 on the street, f (1) = max (Num [0], Num [1]).
To avoid unnecessary double counting, you can create an array dp whose ith element dp[i] is used to hold the result of F (i). If f (i) has calculated the result before, you only need to read the value of dp[i] from the array dp, and you can't repeat the calculation.
code:

import javax.crypto.spec.PSource;
import java.util.Arrays;

public class Rob {
    public int rob(int[] nums) {
        if (nums.length == 0){
            return 0;
        }
        int[] dp = new int[nums.length];
        //Fill the array and set the values in the array to - 1
        Arrays.fill(dp,-1);
        helper(nums,nums.length-1,dp);
        return dp[nums.length-1];
    }

    private void helper(int[] nums, int i, int[] dp) {
        if (i == 0){
            dp[i] = nums[0];
        }else if (i == 1){
            dp[i] = Math.max(nums[0],nums[1]);
        }else if (dp[i] < 0){
            helper(nums,i-2,dp);
            helper(nums,i-1,dp);
            dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i]);
        }
    }
    //Another way of thinking: first find the values of f(0) and f(1), then use the values of f(0) and f(1) to find f(2), use the values of f(1) and f(2) to find f(3), and so on until f(n-1) is found. Complete with a for loop
    //Become this bottom-up thinking.
    public int rob1(int[] nums){
        if (nums.length == 0){
            return 0;
        }
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        if (nums.length > 1){
            dp[1] = Math.max(nums[0],nums[1]);
        }
        for (int i = 2; i < nums.length; i++) {
            dp[i] = Math.max(dp[i-1],dp[i-2] + nums[i]);
        }
        return dp[nums.length - 1];
    }
    //Iterative code with spatial complexity O(1)
    public int rob2(int[] nums){
        if (nums.length == 0){
            return 0;
        }
        //dp[i] only needs to cache two values, and does not need an array with length n, so it can further optimize the space efficiency of the code.
        int[] dp = new int[2];
        dp[0] = nums[0];
        if (nums.length > 1){
            dp[1] = Math.max(nums[0],nums[1]);
        }
        //You can calculate f(i) according to the results of f(i-1) and f(i-2), and then write the results of f(i) into the array where the results of f(i-2) were originally saved. Next, use the results of f(i-1) and f(i) to calculate f (I + 1). Although the value of f(i-2) will be overwritten, it will not be used in the future, so it will not cause any problems.
        for (int i = 2; i < nums.length; i++) {
            dp[i%2] = Math.max(dp[(i-1)%2],dp[(i-2)%2] + nums[i]);
        }
        return dp[(nums.length-1)%2];
    }
    
}

Topics: Algorithm Dynamic Programming