Taro Logo

House Robber IV

Medium
Amazon logo
Amazon
Topics:
ArraysBinary SearchGreedy Algorithms

There are several consecutive houses along a street, each of which has some money inside. A robber wants to steal money from these houses, but refuses to steal from adjacent homes.

The capability of the robber is defined as the maximum amount of money he steals from one house of all the houses he robs.

You are given an integer array nums representing the amount of money in each house (i.e., the i-th house has nums[i] dollars). You are also given an integer k, representing the minimum number of houses the robber must steal from. It is always possible to steal at least k houses.

Return the minimum capability of the robber out of all possible ways to steal at least k houses.

Example 1:

nums = [2,3,5,9], k = 2

Output: 5

Explanation: Ways to rob at least 2 houses:

  • Rob houses at indices 0 and 2. Capability is max(nums[0], nums[2]) = 5.
  • Rob houses at indices 0 and 3. Capability is max(nums[0], nums[3]) = 9.
  • Rob houses at indices 1 and 3. Capability is max(nums[1], nums[3]) = 9.

Therefore, return min(5, 9, 9) = 5.

Example 2:

nums = [2,7,9,3,1], k = 2

Output: 2

Explanation: The optimal way to rob the houses is at indices 0 and 4, leading to a capability of max(nums[0], nums[4]) = 2.

Constraints:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9
  • 1 <= k <= (nums.length + 1) / 2

Solution


Naive Solution (Brute Force)

The most straightforward approach is to generate all possible combinations of non-adjacent houses, calculate the capability for each combination, and then find the minimum capability among all combinations that include at least k houses. This solution is highly inefficient due to the exponential number of possible combinations.

Algorithm:

  1. Generate all possible subsets of houses.
  2. Filter out subsets where adjacent houses are robbed.
  3. Filter out subsets with size less than k.
  4. For each remaining subset, calculate the maximum value (capability).
  5. Return the minimum of all capability values.

Complexity Analysis:

  • Time Complexity: O(2n), where n is the number of houses. Generating all subsets takes O(2n) time.
  • Space Complexity: O(n) in the worst case to store a subset.

Optimal Solution (Binary Search)

A more efficient solution uses binary search. We can binary search the possible range of capabilities. For a given capability cap, we can check if it's possible to rob at least k houses such that the money stolen from each house is at most cap. We can perform this check in linear time.

Algorithm:

  1. Find the minimum and maximum values in the nums array. This will be the range for our binary search.
  2. Perform binary search within this range:
    • For a given mid-value capability, check if we can rob at least k houses such that the value of each robbed house is less than or equal to capability.
    • If we can, it means the answer might be lower, so update the high bound.
    • Otherwise, the answer must be higher, so update the low bound.
  3. Return the final low bound, which will be the minimum capability.

Code:

def minCapability(nums, k):
    def can_rob(capability):
        count = 0
        robbed_prev = False
        for num in nums:
            if num <= capability and not robbed_prev:
                count += 1
                robbed_prev = True
            else:
                robbed_prev = False
        return count >= k

    left, right = min(nums), max(nums)
    ans = right
    while left <= right:
        mid = (left + right) // 2
        if can_rob(mid):
            ans = mid
            right = mid - 1
        else:
            left = mid + 1

    return ans

Explanation:

The can_rob function checks if it's possible to rob at least k houses given a certain capability. It iterates through the houses, and if a house's value is less than or equal to the capability and we haven't robbed the previous house, we rob it and increment the count. The minCapability function then performs a binary search to find the minimum capability that allows us to rob at least k houses.

Complexity Analysis:

  • Time Complexity: O(n log(max(nums) - min(nums))), where n is the number of houses. The binary search takes O(log(max(nums) - min(nums))) time, and the can_rob function takes O(n) time.
  • Space Complexity: O(1). We use only a constant amount of extra space.

Edge Cases:

  • Empty input array: While the prompt states 1 <= nums.length, handle the case gracefully.
  • k = 1: The minimum capability will simply be the minimum value in nums.
  • k = (nums.length + 1) / 2: In this case, we are robbing almost all the houses, with a few skipped over.