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;
    }
};
相关推荐
是小Y啦13 分钟前
leetcode 106.从中序与后续遍历序列构造二叉树
数据结构·算法·leetcode
liuyang-neu23 分钟前
力扣 42.接雨水
java·算法·leetcode
y_dd30 分钟前
【machine learning-12-多元线性回归】
算法·机器学习·线性回归
m0_6312704030 分钟前
标准c语言(一)
c语言·开发语言·算法
万河归海42830 分钟前
C语言——二分法搜索数组中特定元素并返回下标
c语言·开发语言·数据结构·经验分享·笔记·算法·visualstudio
小周的C语言学习笔记35 分钟前
鹏哥C语言36-37---循环/分支语句练习(折半查找算法)
c语言·算法·visual studio
y_dd35 分钟前
【machine learning-七-线性回归之成本函数】
算法·回归·线性回归
小魏冬琅1 小时前
K-means 算法的介绍与应用
算法·机器学习·kmeans
凌肖战2 小时前
力扣上刷题之C语言实现(数组)
c语言·算法·leetcode
秋夫人2 小时前
B+树(B+TREE)索引
数据结构·算法