notes/OJ notes/pages/Leetcode House-Robber.md
2022-09-03 15:17:25 +08:00

4.3 KiB

Leetcode House-Robber

2022-07-20 22:21

Algorithms:

#algorithm #dynamic_programming

Difficulty:

#coding_problem #difficulty-medium

Additional tags:

#leetcode

Revisions:

N/A


Problem

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

Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.

Examples

Example 1:

**Input:** nums = [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:** nums = [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.

Constraints

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 400

Thoughts

[!summary] This is a #dynamic_programming problem.

According to This tuturial, the code can be derived from 3 stages:

Stage 1: Find recursive (unoptimized) solution

The robbing problem can be simplified as follows:

Whether to rob or not?

  • if rob, profit = nums[n] + rob(nums, n - 2)
  • else, profit = rob(nums, n - 1)

The recursive solution can be represented as follows:

Base case: nums.size() = 0 || 1 || 2
Pseudo code:
  • check for base case
  • return max(robbery(nums, n - 1), robbery(nums, n - 2) + nums[n])

Stage 2: Find recursive solution with cache

Since the core of DP as about re-using answers from before, we can cache the answers to make the code faster.

Pseudo code:
  • Check for base case
  • if cache found, return
  • assign the computed value to cache
  • return the cached value

Stage 3: Find iterative solution with caching

By using iterative, we can use less memory than recursion (return stack).

We start from bottom to top, rather than from top to down, and use the cached answer to proceed to the final answer

Stage 4: Optimize it by using variables rather than hash table based caching

This can be different from problem to problem, but for this case, we achieve constant space complexity using variables.

Solution

Stage 1:

TLE, I didn't save this one

Stage 2:

class Solution {
  vector<int> cache;
  int robbery(vector<int> &nums, int nextLoc) {
    // base cases:
    // nextLoc == 0, return nums[1]
    // nextLoc == 1, return nums[2]
    if (nextLoc < 0) {
      return 0;
    }

    if (cache[nextLoc] != -1) {
      return cache[nextLoc];
    }

    cache[nextLoc] = max(robbery(nums, nextLoc - 1),
                         robbery(nums, nextLoc - 2) + nums[nextLoc]);

    return cache[nextLoc];
  }

public:
  int rob(vector<int> &nums) {
    // Version one
    // Recursion
    // rob current store: nums[i] + rob(i - 2)
    // don't rob current home: rob(i - 1)
    cache = vector<int>(nums.size(), -1);

    return robbery(nums, nums.size() - 1);
  }
};

Stage 3:


Stage 4:

class Solution {
public:
  int rob(vector<int> &nums) {
    // iterative, from the buttom up
    // We can utilize the hash map feature

    int size = nums.size();
    if (size == 0) {
      return 0;
    } else if (size == 1) {
      return nums[0];
    }

    int prev1, prev2, next; // next: i + 1

    int curLoc = 1;
    prev1 = nums[0];               // i - 1
    prev2 = max(nums[0], nums[1]); // i
    next = prev2;
    while (curLoc < size - 1) {
      // cache[curLoc + 1] = max(cache[curLoc - 1] + nums[curLoc + 1] ,
      // cache[curLoc]);
      next = max(prev1 + nums[curLoc + 1], prev2);
      prev1 = prev2;
      prev2 = next;
      curLoc++;
    }
    return next;
  }
};