There are several consecutive houses along a street, each of which has some money inside. There is also a robber, who wants to steal money from the homes, but he refuses to steal from adjacent homes.
The capability of the robber is the maximum amount of money he steals from one house of all the houses he robbed.
You are given an integer array nums
representing how much money is stashed in each house. More formally, the i<sup>th</sup>
house from the left has nums[i]
dollars.
You are also given an integer k
, representing the minimum number of houses the robber will steal from. It is always possible to steal at least k
houses.
Return the minimum capability of the robber out of all the possible ways to steal at least k
houses.
Example:
nums = [2,3,5,9], k = 2
Output: 5
Explanation: There are three ways to rob at least 2 houses:
## Data Structures and Algorithms: Minimum Capability to Rob Houses
### Problem Description
You are a robber planning to rob houses along a street. Each house has a certain amount of money stashed, but there's a constraint: you cannot rob adjacent houses. Your capability is defined as the maximum amount of money you steal from any single house. Given an array `nums` representing the amount of money in each house and an integer `k` representing the minimum number of houses you must rob, find the minimum capability required to rob at least `k` houses.
### Naive Approach (Brute Force)
A brute-force solution would involve generating all possible combinations of non-adjacent houses, checking if the number of houses robbed is at least `k`, and then finding the minimum of the maximum values among those valid combinations. However, this approach is highly inefficient due to the exponential number of combinations to check.
### Optimal Approach (Binary Search)
We can use binary search to find the minimum capability. The idea is to binary search over the possible range of capabilities (from the minimum to the maximum amount of money in the houses). For each potential capability value, we check if it's possible to rob at least `k` houses without exceeding that capability. If it is, we try a smaller capability; otherwise, we try a larger one.
```python
def minCapability(nums, k):
left, right = min(nums), max(nums)
def can_rob(capability):
count = 0
robbed = False
for num in nums:
if num <= capability and not robbed:
count += 1
robbed = True
else:
robbed = False
return count >= k
while left < right:
mid = (left + right) // 2
if can_rob(mid):
right = mid
else:
left = mid + 1
return left
Explanation:
left
is initialized to the minimum value in nums
.right
is initialized to the maximum value in nums
.left < right
, we calculate the mid
value.can_rob(mid)
function checks if we can rob at least k
houses with the given capability
.can_rob(mid)
returns True
, it means the current capability mid
is sufficient, so we try to reduce the capability by setting right = mid
.can_rob(mid)
returns False
, it means the current capability mid
is not sufficient, so we need to increase the capability by setting left = mid + 1
.left
will converge to the minimum capability that allows us to rob at least k
houses. We return left
.Example:
nums = [2, 3, 5, 9], k = 2
left = 2
, right = 9
mid = (2 + 9) // 2 = 5
can_rob(5)
returns True
(we can rob houses with values 2 and 5), so right = 5
mid = (2 + 5) // 2 = 3
can_rob(3)
returns False
(we can only rob house with value 2 or 3 individually), so left = 4
mid = (4 + 5) // 2 = 4
can_rob(4)
returns False
, so left = 5
left = 5
.can_rob
function runs in O(n) time, where n is the number of houses (length of nums
).left
, right
, mid
, count
, and robbed
.nums
is empty, we should return 0 or handle it based on the problem's specific requirements.k
is 0, it means we don't need to rob any houses, so the minimum capability should be 0 if all house have money.k
is greater than 1 and we can't choose adjacent houses, we have to choose houses so that the minimum capability condition is met.def minCapability(nums, k):
if not nums:
return 0 # Or raise an exception if appropriate
left, right = min(nums), max(nums)
def can_rob(capability):
count = 0
robbed = False
for num in nums:
if num <= capability and not robbed:
count += 1
robbed = True
else:
robbed = False
return count >= k
while left < right:
mid = (left + right) // 2
if can_rob(mid):
right = mid
else:
left = mid + 1
return left