2560. 打家劫舍 IV

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

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

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

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

另给你一个整数 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 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9
  • 1 <= k <= (nums.length + 1)/2

题解:这题的本质是找到一个最小的num值使得至少存在k个不相邻的元素它们的最大值是num,由于num值越小那么能找到的k的值越小,num值越大,能找到的k的值越大,因此满足逻辑二分的条件。
二分+贪心,可以贪心地从前往后窃取,若窃取了当前的索引,则跳过下一个索引,不会影响到后序的计数。
当前房屋 nums[i]偷了的话,剩下可以偷的是 nums[i+2] 到 nums[−1],如果当前房屋不偷,就算 nums[i+1]偷了,那么剩下可偷的是 nums[i+3]到 nums[−1],算下来的结果肯定是 <= 的,所以不如直接偷了 nums[i].

有没有可能,二分出来的答案,不在 nums 中呢?
可以把num想象成一根线,将nums中大于它的和小于它的元素分在上下两部分,下半部分的元素个数是k个。如果num不在nums里,可以想象将num这根线慢慢向下移动,只要没有碰到nums中的元素,num下半部分的元素始终是k个。其实就是找的二分法左侧边界,再小就不符合了

code:

class Solution {
    public int minCapability(int[] nums, int k) {
        int lower = Arrays.stream(nums).min().getAsInt();
        int upper = Arrays.stream(nums).max().getAsInt();
        while (lower <= upper) {
            int middle = (lower + upper) / 2;
            int count = 0;
            boolean visited = false;
            for (int x : nums) {
                if (x <= middle && !visited) {
                    count++;
                    visited = true;
                } else {
                    visited = false;
                }
            }
            if (count >= k) {
                upper = middle - 1;
            } else {
                lower = middle + 1;
            }
        }
        return lower;
    }
}


 

你可能感兴趣的:(算法,leetcode,数据结构)