【每日一题】力扣:打家劫舍 IV

打家劫舍 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

class Solution {
public:
    bool check(vector<int>& nums, int k, int ability){
        // dp[i] 表示到第 i 间房屋时,可偷窃房屋的最大数量
        vector<int> dp(nums.size());
        dp[0] = nums[0] <= ability ? 1 : 0;
        dp[1] = max(dp[0], nums[1] <= ability ? 1 : 0);
        for(int i = 2; i < nums.size(); ++i){
            if(nums[i] <= ability){
                // 选择偷 或 不偷
                dp[i] = max(dp[i - 2] + 1, dp[i - 1]);
            }
            else{
                dp[i] = dp[i - 1];
            }
        }
        return dp[nums.size() - 1] >= k;
    }
  
    int minCapability(vector<int>& nums, int k) {
        if(k == 1){
            return *min_element(nums.begin(), nums.end());
        }
        // 对房屋的金钱进行排序(也就是潜在的能力值)
        vector<int> ability(nums);
        sort(ability.begin(), ability.end());
        // 对 “潜在的能力值” 开始二分搜索
        int L = 0, R = ability.size() - 1;
        while(L <= R){
            int mid = L + ((R - L) >> 1);
            if(check(nums, k, ability[mid])){
                R = mid - 1;
            }else{
                L = mid + 1;
            }
        }
        // 返回最小的窥窃能力值
        return ability[L];
    }
};

你可能感兴趣的:(#,力扣【每日一题】,leetcode,算法)