← DSA
MEDIUM

House Robber II

PracticeNeetCode ↗LeetCode ↗

Same rules as House Robber, but the houses are arranged in a circle — house 0 and the last house are now neighbors too. Return the most money you can rob without robbing two adjacent houses.

Example

Input nums = [2,3,2]
Output 3

Key Pointers

Step-by-Step Analysis

  1. If there's only one house, return its value directly.
  2. Run the linear House Robber logic on every house except the last.
  3. Run the same linear logic on every house except the first.
  4. Return the larger of the two results.

Complexity

Time: O(n) — Space: O(1)

Code

def rob(nums: list[int]) -> int:
    if len(nums) == 1:
        return nums[0]

    def rob_linear(houses: list[int]) -> int:
        rob1, rob2 = 0, 0
        for n in houses:
            rob1, rob2 = rob2, max(n + rob1, rob2)
        return rob2

    return max(rob_linear(nums[:-1]), rob_linear(nums[1:]))

Code Explanation

How the solution above works, piece by piece.

  1. A single house: just rob it.
  2. rob_linear is the House Robber solution for a straight street.
  3. The circle only adds one constraint: house 0 and house n−1 can't both be robbed. Every valid plan therefore avoids at least one of them.
  4. So the answer is the better of rob_linear(nums[:-1]) (never rob the last) and rob_linear(nums[1:]) (never rob the first).
  5. Two linear passes: O(n) time; the slices use O(n) space (index bounds would make it O(1)).

Visual Walkthrough

Running it on nums = [2, 3, 2]:

Circular street split into two straight streetshouses in a circle: first and last are neighboursskip last232linear robber on [2, 3] → 3skip first232linear robber on [3, 2] → 3answer = max(3, 3) = 3
Because the first and last houses touch, they can't both be robbed. So solve two ordinary House Robber problems, one without the last house and one without the first, and take the better. Here both give 3 (rob the middle house).
case 1case 2

Video Explanation

NeetCode — Dynamic Programming, LeetCode 213