Leetcode.2560 打家劫舍 IV

题目链接

Leetcode.2560 打家劫舍 IV rating : 2081

题目描述

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

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

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

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

另给你一个整数 k k k ,表示窃贼将会窃取的 最少 房屋数。小偷总能窃取至少 k k k 间房屋。

返回小偷的 最小 窃取能力。

示例 1:

输入:nums = 2,3,5,9, k = 2

输出:5

解释:

小偷窃取至少 2 间房屋,共有 3 种方式:

  • 窃取下标 0 和 2 处的房屋,窃取能力为 max(nums0, nums2) = 5 。
  • 窃取下标 0 和 3 处的房屋,窃取能力为 max(nums0, nums3) = 9 。
  • 窃取下标 1 和 3 处的房屋,窃取能力为 max(nums1, nums3) = 9 。
    因此,返回 min(5, 9, 9) = 5 。

示例 2:

输入:nums = 2,7,9,3,1, k = 2

输出:2

解释:共有 7 种窃取方式。窃取能力最小的情况所对应的方式是窃取下标 0 和 4 处的房屋。返回 max(nums0, nums4) = 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 numsi \leq 10^9 1≤numsi≤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 numsi numsi,我们需要讨论:

  • 如果 n u m s i > x numsi > x numsi>x,说明当前 n u m s i numsi numsi 我们是不能选的,所以 f ( i ) = f ( i − 1 ) f(i) = f(i - 1) f(i)=f(i−1);
  • 如果 n u m s i ≤ x numsi \leq x numsi≤x,说明当前 n u m s i numsi numsi 我们可以选,所以 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;
    }
};
相关推荐
专注仿真4 小时前
引擎扩展性与集成设计深度剖析:从 14 个扩展点到 DIS→HLA 演进之路
开发语言·算法·仿真引擎·推演引擎
码爸4 小时前
支持向量机介绍与示例
算法·机器学习·支持向量机
怕浪猫4 小时前
2028编程圈很火的10个Skills
算法·面试·github
Nil2089 小时前
leetcode 198打家劫舍
算法·leetcode·职场和发展
Shaoshing9 小时前
前缀和与差分
java·数据结构·算法·前缀和·差分
loulanyue_10 小时前
构建房产认知决策智能:Harness底座与AI自进化的技术实践——读贝壳首席算法科学家尹俊希2026云栖专场演讲
人工智能·算法
碧海银沙音频科技研究院10 小时前
基于炬芯ATS录音卡BLE控制协议
人工智能·嵌入式硬件·算法·语音识别
suhan11 小时前
【数据结构】三、栈和队列:6.链队列、双端队列、队列的应用(树的层次遍历、广度优先BFS、先来先服务FCFS)
数据结构·后端·算法
姜鱼问生11 小时前
Docker Volume 备份与恢复实战:不停机迁移数据
后端·算法·架构
suhan11 小时前
【数据结构】三、栈和队列:5.顺序队列(循环队列)(初始化,判空判满,入队,出队,实例)
数据结构·后端·算法