沿街有一排连续的房屋。每间房屋内都藏有一定的现金。现在有一位小偷计划从这些房屋中窃取现金。
由于相邻的房屋装有相互连通的防盗系统,所以小偷 不会窃取相邻的房屋 。
小偷的 窃取能力 定义为他在窃取过程中能从单间房屋中窃取的 最大金额 。
给你一个整数数组 nums
表示每间房屋存放的现金金额。形式上,从左起第 i
间房屋中放有 nums[i]
美元。
另给你一个整数 k
,表示窃贼将会窃取的 最少 房屋数。小偷总能窃取至少 k
间房屋。
返回小偷的 最小 窃取能力。
示例 1:
输入:nums = [2,3,5,9], k = 2 输出:5 解释: 小偷窃取至少 2 间房屋,共有 3 种方式: - 窃取下标 0 和 2 处的房屋,窃取能力为 max(nums[0], nums[2]) = 5 。 - 窃取下标 0 和 3 处的房屋,窃取能力为 max(nums[0], nums[3]) = 9 。 - 窃取下标 1 和 3 处的房屋,窃取能力为 max(nums[1], nums[3]) = 9 。 因此,返回 min(5, 9, 9) = 5 。
示例 2:
输入:nums = [2,7,9,3,1], k = 2 输出:2 解释:共有 7 种窃取方式。窃取能力最小的情况所对应的方式是窃取下标 0 和 4 处的房屋。返回 max(nums[0], nums[4]) = 2 。
提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
1 <= k <= (nums.length + 1)/2
题解:这题的本质是找到一个最小的num值使得至少存在k个不相邻的元素它们的最大值是num,由于num值越小那么能找到的k的值越小,num值越大,能找到的k的值越大,因此满足逻辑二分的条件。
二分+贪心,可以贪心地从前往后窃取,若窃取了当前的索引,则跳过下一个索引,不会影响到后序的计数。
当前房屋 nums[i]偷了的话,剩下可以偷的是 nums[i+2] 到 nums[−1],如果当前房屋不偷,就算 nums[i+1]偷了,那么剩下可偷的是 nums[i+3]到 nums[−1],算下来的结果肯定是 <= 的,所以不如直接偷了 nums[i].
有没有可能,二分出来的答案,不在 nums 中呢?
可以把num想象成一根线,将nums中大于它的和小于它的元素分在上下两部分,下半部分的元素个数是k个。如果num不在nums里,可以想象将num这根线慢慢向下移动,只要没有碰到nums中的元素,num下半部分的元素始终是k个。其实就是找的二分法左侧边界,再小就不符合了
code:
class Solution {
public int minCapability(int[] nums, int k) {
int lower = Arrays.stream(nums).min().getAsInt();
int upper = Arrays.stream(nums).max().getAsInt();
while (lower <= upper) {
int middle = (lower + upper) / 2;
int count = 0;
boolean visited = false;
for (int x : nums) {
if (x <= middle && !visited) {
count++;
visited = true;
} else {
visited = false;
}
}
if (count >= k) {
upper = middle - 1;
} else {
lower = middle + 1;
}
}
return lower;
}
}