力扣——2560. 打家劫舍 IV
题目描述:
沿街有一排连续的房屋。每间房屋内都藏有一定的现金。现在有一位小偷计划从这些房屋中窃取现金。
由于相邻的房屋装有相互连通的防盗系统,所以小偷 不会窃取相邻的房屋 。
小偷的 窃取能力 定义为他在窃取过程中能从单间房屋中窃取的 最大金额 。
给你一个整数数组 nums
表示每间房屋存放的现金金额。形式上,从左起第 i
间房屋中放有 nums[i]
美元。
另给你一个整数 k
,表示窃贼将会窃取的 最少 房屋数。小偷总能窃取至少 k
间房屋。
返回小偷的 最小 窃取能力。
示例 :
输入: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 。
分析:
力扣的每日一题真的是和小偷杠上了哈哈,连续做了三天打家劫舍。这题一开始没有思路,后面看了题解才解出来的,拖了大伙的后腿。
题目理解:
- 不会窃取相邻房屋 dp[i] = max(dp[i-1],dp[i-2]+v) 大概是这种格式的动态规划
- 窃贼最少窃取 k 间房屋的情况下,让单间房屋窃取的最大金额最小,最大值最小问题,可以用二分答案解决
思路
- 求出数组中的最大最小值,答案一定就在这些值之中,得到二分的范围
- 假设房前窃取的最大金额是 x, 那么如果当前房屋超过了 x,则无法窃取当前房屋
- 否则可以窃取当前房屋计数 1,也就是 max(dp[i-1],dp[i-2]+v) 这个里面的 v 值看当前金额与 x 的比较结果,不超过 x 计数 1,否则为 0
- 如果再窃取能力是 x 的情况下,能窃取到 k 间以上的房屋,则尝试缩小窃取能力(因为答案要最小的窃取能力)
- 否则说明 x 不是可行解,需要找到 x+1 以上的房屋才能获得到可行解
代码解析:
class Solution2560 {
public int minCapability(int[] nums, int k) {
int n = nums.length;
if(n==1) return nums[0];
int left = Integer.MAX_VALUE;
int right = Integer.MIN_VALUE;
for(int num:nums){
left = Math.min(num,left);
right = Math.max(num,right);
}
while(left<right){
int mid = (right-left)/2+left;
if(check(nums,mid,k)){
right = mid;
}else{
left = mid+1;
}
}
return right;
}
private boolean check(int[] nums, int v, int k){
int n = nums.length;
long[] dp = new long[n];
dp[0]=nums[0]<=v?1:0;
dp[1]=nums[1]<=v?1:0;
dp[1] = Math.max(dp[0],dp[1]);
for(int i = 2; i < n; i++){
int add = nums[i]<=v?1:0;
dp[i] = Math.max(add+dp[i-2],dp[i-1]);
}
return dp[n-1]>=k;
}
}
感谢您的观看,我的博客地址:http://47.115.223.247:2001/