House Robber II
Master this topic with zero to advance depth.
House Robber II
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system 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.
Visual Representation
nums = [2, 3, 2]
Circle Layout:
(2) -- (3)
| |
( ) -- (2)
Options:
1. Rob House 0: Cannot rob House 1 or House 2. Result: 2
2. Rob House 1: Cannot rob House 0 or House 2. Result: 3
Result: 3Examples
You cannot rob house 1 (money = 2) and then rob house 3 (money = 2), because they are adjacent houses.
Level I: Brute Force (Recursion)
Intuition
To handle the circular constraint, we can either rob the first house (forcing us to skip the last) or skip the first house (allowing us to potentially rob the last). We run two separate recursions and compare results.
Thought Process
rob(nums, start, end)is a recursive function for a linear range.- In circular
nums[0...n-1]:- Option 1: Rob from
0ton-2. - Option 2: Rob from
1ton-1.
- Option 1: Rob from
- Return
max(Option 1, Option 2).
Pattern Identification
Circular to Linear Reduction using Recursion.
Detailed Dry Run
nums = [2, 3, 2]
- solve(0, 1): max(2+f(-1), f(0)) = 2. Skip last house.
- solve(1, 2): max(2+f(0), f(1)) = 2. Skip first house. Result: 2
Level II: Top-Down DP with Helper
Intuition
We reduce the circular problem into two linear House Robber I problems (skip first house or skip last house) and apply memoization on each.
Visual
nums = [2, 3, 2]
Case 1: Skip last -> rob [2, 3] -> memoized linear rob
Case 2: Skip first -> rob [3, 2] -> memoized linear rob
Result: max(3, 3) = 3Detailed Dry Run
Call memoized robLinear on [2, 3] → 3. Call memoized robLinear on [3, 2] → 3. max = 3.
⚠️ Common Pitfalls & Tips
Since lru_cache in Python captures closure variables, use tuples as arguments for the circular-to-linear reduction to avoid cache collisions between the two sub-problems.
Level III: Dynamic Programming (Linear Sub-problems)
Intuition
The circular constraint means we can either rob the first house OR the last house, but never both. This simplifies the circular problem into two linear House Robber problems:
- Rob houses from index
0ton-2(exclude last). - Rob houses from index
1ton-1(exclude first).
Thought Process
- If
n=1, returnnums[0]. - Calculate
maxLoot1 = houseRobberLinear(nums[0...n-2]). - Calculate
maxLoot2 = houseRobberLinear(nums[1...n-1]). - Return
max(maxLoot1, maxLoot2).
Pattern Identification
This is Reducing Circular to Linear. We reuse the standard House Robber logic twice.
Detailed Dry Run
nums = [2, 3, 2]
| Step | Subset | Max Loot (Linear) |
|---|---|---|
| 1 | [2, 3] | max(2, 3) = 3 |
| 2 | [3, 2] | max(3, 2) = 3 |
| Final | max(3, 3) | 3 |
⚠️ Common Pitfalls & Tips
Don't forget the base case for n=1. If you don't handle it, slicing or indexing might fail. Also, ensure both linear calls exclude at least one house to break the circular dependency.
Found an issue or have a suggestion?
Help us improve! Report bugs or suggest new features on our Telegram group.