House Robber - dynamic programming

I try to do semantic programming this time. I will write my ideas in form of code comments and use semantic naming for variables as I can.
The code in the solution was not only written for solving the question, but also written for IN-ORDER READING. That means, I have carefully designed in a way that you better read my code from

  • the first line (class definition)
  • then some next lines (some private helper functions)
  • and and the last public method (the primary public method called by outside).

You are not supposed to SCAN the code. You are supposed to LINE BY LINE read the code. Don't try to SCAN roughly, that doesn't help you understand the code quickly. But if you patiently read it, in 3 minutes you understand the code perfectly. (Assuming that you have fully understood the question.)

Question

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
Given [3, 8, 4], return 8.
Challenge
O(n) time and O(1) memory.

Solution

/**
 *  Solution idea:
 *  case 1: If you rob this house, previous house was not robbed for sure.
 *  case 2: If you can't rob this house, then previous house was already robbed for sure.
 *  You want the max amount amongst the two cases.
 *
 *  FORMULA:
 *  max robbed total of previous N houses =
 *      Math.max("max robbed total of previous N - 1 houses" + 0, "max robbed total of previous N - 2 houses" + money of this house)
 *
 *  In this question, we only want the last result. That means we only need to compute two states: "N - 1 case" and "N - 2 case"
 *  And these two states can be derived from earlier states. Let's do dynamic programming.
 *
 */
public class Solution {

    /**
     *  Image we hold a flag and pass the houses one by one.
     *  f(n) means PREVIOUS n houses of the flag.
     *  f(n) = max(f(n-1), f(n - 2) + houseMoney[n - 1])
     *  you need to remember only two results: f(n - 1) and f(n - 2) to get next result
     */
    private final int numberOfStates = 2;
    private final long[] maxTotal = new long[this.numberOfStates];

    /**
     *
     * @param previousNHouses
     * @return real index of result array
     */
    private int indexOf(int previousNHouses) {
        return previousNHouses % this.numberOfStates;
    }

    /**
     * initialize states of result array
     * @param houseMoney array of money in each house
     */
    private void initResultArray(int[] houseMoney) {
        // no previous houses, no money
        this.maxTotal[0] = 0;
        // only one previous house (which is at index 0), rob it undoubtedly
        this.maxTotal[1] = houseMoney[0];
    }

    /**
     * update the result array
     * @param previousNHouses
     * @param houseMoney
     */
    private void updateResult(int previousNHouses, int[] houseMoney) {
        // FORMULA: index = length - 1
        int indexOfPreviousHouse = previousNHouses - 1;

        // two cases
        long moneyWithoutPreviousHouse =  this.maxTotal[indexOf(previousNHouses - 1)];
        long moneyWithPreviousHouse = this.maxTotal[indexOf(previousNHouses - 2)] + houseMoney[indexOfPreviousHouse];

        // pick the largest
        this.maxTotal[indexOf(previousNHouses)] = Math.max(
                moneyWithoutPreviousHouse,
                moneyWithPreviousHouse
        );
    }

    /*
     * @param houseMoney: An array of non-negative integers
     * @return: The maximum amount of money you can rob tonight
     */
    public long houseRobber(int[] houseMoney) {

        /**
         *  edge cases
         */
        if (houseMoney.length == 0) return 0;

        /**
         *  Initialize states of dynamic programming
         */
        initResultArray(houseMoney);

        /**
         *  Perform dynamic programming calculation
         */
        for(int previousNHouses = 2; previousNHouses <= houseMoney.length; previousNHouses++)
            updateResult(previousNHouses, houseMoney);

        /**
         *  result was ready after dynamic programming calculation
         */
        return this.maxTotal[indexOf(houseMoney.length)];
    }

}

你可能感兴趣的:(House Robber - dynamic programming)