Leetcode.2560 打家劫舍 IV

题目链接

Leetcode.2560 打家劫舍 IV rating : 2081

题目描述

沿街有一排连续的房屋。每间房屋内都藏有一定的现金。现在有一位小偷计划从这些房屋中窃取现金。

由于相邻的房屋装有相互连通的防盗系统,所以小偷 不会窃取相邻的房屋

小偷的 窃取能力 定义为他在窃取过程中能从单间房屋中窃取的 最大金额

给你一个整数数组 n u m s nums nums 表示每间房屋存放的现金金额。形式上,从左起第 i i i 间房屋中放有 n u m s [ i ] nums[i] nums[i] 美元。

另给你一个整数 k k k ,表示窃贼将会窃取的 最少 房屋数。小偷总能窃取至少 k 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 ≤ n u m s . l e n g t h ≤ 1 0 5 1 \leq nums.length \leq 10^5 1≤nums.length≤105
  • 1 ≤ n u m s [ i ] ≤ 1 0 9 1 \leq nums[i] \leq 10^9 1≤nums[i]≤109
  • 1 ≤ k ≤ ( n u m s . l e n g t h + 1 ) / 2 1 \leq k \leq (nums.length + 1)/2 1≤k≤(nums.length+1)/2

解法:二分 + dp

我们定义 f ( i , x ) f(i,x) f(i,x) 为 能从 n u m s nums nums前 i i i 个房间中选的 不大于 x x x 的最多房间个数。

如果 f ( n , x ) ≥ k f(n,x) \geq k f(n,x)≥k ,说明 能找到 至少 k k k 个 不大于 x x x 的房间,那么 x x x 就是答案之一。

如果 f ( n , x ) < k f(n,x) < k f(n,x)<k ,说明 不能找到 至少 k k k 个 不大于 x x x 的房间,那么我们需要适当的增大 x x x。

所以我们可以使用二分,来得到一个最小的满足要求的 x x x,就是答案。

对于 n u m s [ i ] nums[i] nums[i],我们需要讨论:

  • 如果 n u m s [ i ] > x nums[i] > x nums[i]>x,说明当前 n u m s [ i ] nums[i] nums[i] 我们是不能选的,所以 f ( i ) = f ( i − 1 ) f(i) = f(i - 1) f(i)=f(i−1);
  • 如果 n u m s [ i ] ≤ x nums[i] \leq x nums[i]≤x,说明当前 n u m s [ i ] nums[i] nums[i] 我们可以选,所以 f ( i ) = m a x { f ( i ) , f ( i − 2 ) + 1 } f(i) = max \{ f(i) ,f(i - 2) + 1 \} f(i)=max{f(i),f(i−2)+1};

在实现上我们可以只使用两个变量 f 0 f0 f0 和 f 1 f1 f1 来代替数组。

时间复杂度: O ( n × l o g n ) O(n \times logn) O(n×logn)

C++代码:

cpp 复制代码
class Solution {
public:
    int minCapability(vector<int>& nums, int k) {
        int n = nums.size();

        auto check = [&](int t) -> bool{
            int f0 = 0 , f1 = 0;
            for(auto x:nums){
                if(x > t) f0 = f1;
                else{
                    int temp = f1;
                    f1 = max(f1,f0 + 1);
                    f0 = temp;
                }
            }
            return f1 >= k;
        };

        int l = 0 , r = 1e9;
        while(l < r){
            int mid = (l + r) >> 1;
            if(check(mid)) r = mid;
            else l = mid + 1;
        }

        return l;
    }
};
相关推荐
SsummerC23 分钟前
【leetcode100】杨辉三角
python·leetcode·动态规划
杰杰批24 分钟前
力扣热题100——普通数组(不普通)
算法·leetcode
CodeSheep24 分钟前
稚晖君又添一员猛将!
人工智能·算法·程序员
天天扭码25 分钟前
一分钟解决“3.无重复字符的最长字串问题”(最优解)
前端·javascript·算法
风靡晚30 分钟前
一种改进的CFAR算法用于目标检测(解决多目标掩蔽)
人工智能·算法·目标检测·目标跟踪·信息与通信·信号处理
香宝的最强后援XD44 分钟前
区域填充算法
算法
所以遗憾是什么呢?1 小时前
扩展欧几里得算法【Exgcd】的内容与题目应用
数学·算法·数论·扩展欧几里得·exgcd
haaaaaaarry1 小时前
【贪心】C++ 活动安排问题
开发语言·c++·算法·贪心
ChengZUOZZZ1 小时前
蓝桥杯题目:二维前缀和
java·算法·蓝桥杯
槐月杰6 小时前
C语言中冒泡排序和快速排序的区别
c语言·算法·排序算法