notes/OJ notes/pages/Leetcode House-Robber.md

183 lines
4.4 KiB
Markdown
Raw Normal View History

2022-07-20 22:44:44 +08:00
# Leetcode House-Robber
#### 2022-07-20 22:21
> ##### Algorithms:
> #algorithm #dynamic_programming
> ##### Difficulty:
> #coding_problem #difficulty-medium
> ##### Additional tags:
> #leetcode
> ##### Revisions:
> N/A
##### Related topics:
```expander
tag:#dynamic_programming
```
##### Links:
- [Link to problem](https://leetcode.com/problems/house-robber/)
- [Tutorial and explanation on DP](https://leetcode.com/problems/house-robber/discuss/156523/From-good-to-great.-How-to-approach-most-of-DP-problems.)
___
### 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:**
```markdown
**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:**
```markdown
**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](https://leetcode.com/problems/house-robber/discuss/156523/From-good-to-great.-How-to-approach-most-of-DP-problems.), 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:
```cpp
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:
```cpp
2022-07-20 22:51:09 +08:00
```
#### Stage 4:
```cpp
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;
}
};
```