【二分答案】三道经典例题入门二分

目录

例题一

例题二

例题三


例题一

力扣875.爱吃香蕉的珂珂

珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。

珂珂可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。

珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。

返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。

示例 1:

输入:piles = [3,6,7,11], h = 8
输出:4
示例 2:

输入:piles = [30,11,23,4,20], h = 5
输出:30
示例 3:

输入:piles = [30,11,23,4,20], h = 6
输出:23
 

提示:

1 <= piles.length <= 104
piles.length <= h <= 109
1 <= piles[i] <= 109

解题思路:

我们知道,二分要有边界和单调性,在二分答案中,边界很容易看出来,这题是1和piles里最大的数。而单调性,这题就是对于一个速度,当这个速度小于某个值(就是要求的临界速度)时,不符合要求,当成是0,大于这个临界速度,当成是1,于是化成在数组0,0,0。。。1,1,1中寻找下标最小的1。

class Solution {
public:
    bool check(vector<int>& piles,int h,int ans)
    {   
        int sum=0;
        for(int i=0;i<piles.size();i++)
        {
            sum+=(piles[i]-1)/ans+1;//遍历每个piles[i],计算出该ans下的时间
        }
        if(sum<=h)return true;//如果时间足够小,就是可以满足
        else return false;
    }
    int minEatingSpeed(vector<int>& piles, int h) {
        int l=1,r=1000000000;          //初始化边界
        while(l<r)
        {
            int mid=l+(r-l)/2;        //这里防止溢出,然后是向左寻找答案的模板
            if(check(piles,h,mid))r=mid;
            else l=mid+1;
        }
        return l;
    }
};

例题二

力扣1552.两球之间的磁力

在代号为 C-137 的地球上,Rick 发现如果他将两个球放在他新发明的篮子里,它们之间会形成特殊形式的磁力。Rick 有 n 个空的篮子,第 i 个篮子的位置在 position[i] ,Morty 想把 m 个球放到这些篮子里,使得任意两球间 最小磁力 最大。

已知两个球如果分别位于 x 和 y ,那么它们之间的磁力为 |x - y| 。

给你一个整数数组 position 和一个整数 m ,请你返回最大化的最小磁力。

示例 1:

输入:position = [1,2,3,4,7], m = 3
输出:3
解释:将 3 个球分别放入位于 1,4 和 7 的三个篮子,两球间的磁力分别为 [3, 3, 6]。最小磁力为 3 。我们没办法让最小磁力大于 3 。
示例 2:

输入:position = [5,4,3,2,1,1000000000], m = 2
输出:999999999
解释:我们使用位于 1 和 1000000000 的篮子时最小磁力最大。
 

提示:

n == position.length
2 <= n <= 10^5
1 <= position[i] <= 10^9
所有 position 中的整数 互不相同 。
2 <= m <= position.length

 解题思路:

其实看这问题“返回最大化的最小磁力”,就知道这是二分答案的题目。首先,只需要考虑相邻之间的磁力,因为不相邻的球的磁力肯定比相邻的大,我们要的是最小磁力。

其次,我们要贪心地尽可能将球放得相隔远一点,那最左边的篮子你放不放球?思考一下,放最左边百利而无一害,所以必须放。

还需要注意的是,对于要check的一个磁力,是不是每个球的间隔必须是这么大?不必要。我们每次放都是放满足大于等于这个磁力的最小磁力。

那有人就要说了,如果每个磁力都大于这个check的磁力怎么办?不要紧,关键看能不能放得下m个球,如果放得下,说明check的磁力够小,否则太大。依次来二分答案即可

class Solution {
public:
    bool check(vector<int>& position,int m,int k)
    {
        int pre=position[0],sum=1;          //第一个篮子必放
        for(int i=1;i<position.size();i++)
        {
            if(position[i]-pre>=k)         //找到能放的球最左边的篮子
            {
                sum++;pre=position[i];
            }
        }
        if(sum<m)return false;
        return true;
    }
    int maxDistance(vector<int>& position, int m) {
        sort(position.begin(),position.end());  //将篮子从左到右排
        int l=1,r=position.back()-position[0];  //边界
        while(l<r)
        {
            int mid=l+(r-l+1)/2;                //注意是最大化答案,所以是向右找的模板
            if(check(position,m,mid))l=mid;
            else r=mid-1;
        }
        return l;
    }
};

例题三

力扣1760.袋子里最少数目的球

给你一个整数数组 nums ,其中 nums[i] 表示第 i 个袋子里球的数目。同时给你一个整数 maxOperations 。

你可以进行如下操作至多 maxOperations 次:

选择任意一个袋子,并将袋子里的球分到 2 个新的袋子中,每个袋子里都有 正整数 个球。
比方说,一个袋子里有 5 个球,你可以把它们分到两个新袋子里,分别有 1 个和 4 个球,或者分别有 2 个和 3 个球。
你的开销是单个袋子里球数目的 最大值 ,你想要 最小化 开销。

请你返回进行上述操作后的最小开销。

示例 1:

输入:nums = [9], maxOperations = 2
输出:3
解释:
- 将装有 9 个球的袋子分成装有 6 个和 3 个球的袋子。[9] -> [6,3] 。
- 将装有 6 个球的袋子分成装有 3 个和 3 个球的袋子。[6,3] -> [3,3,3] 。
装有最多球的袋子里装有 3 个球,所以开销为 3 并返回 3 。
示例 2:

输入:nums = [2,4,8,2], maxOperations = 4
输出:2
解释:
- 将装有 8 个球的袋子分成装有 4 个和 4 个球的袋子。[2,4,8,2] -> [2,4,4,4,2] 。
- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,4,4,4,2] -> [2,2,2,4,4,2] 。
- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,4,4,2] -> [2,2,2,2,2,4,2] 。
- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,2,2,4,2] -> [2,2,2,2,2,2,2,2] 。
装有最多球的袋子里装有 2 个球,所以开销为 2 并返回 2 。
示例 3:

输入:nums = [7,17], maxOperations = 2
输出:7
 

提示:

1 <= nums.length <= 105
1 <= maxOperations, nums[i] <= 109

 解题思路:

这题也是个模板题,二分出一个答案,检验时遍历nums,找一下规律可知,要将nums[i]分成最多球也小于等于ans,需要(nums[i]-1)/ans下操作,套公式即可。


还有一些经典例题,供读者练习:

力扣1283.使结果不超过阈值的最小除数

P2440 木材加工

P2678 跳石头

P1824 进击的奶牛


如果觉得博文有用,不妨点点关注,你的支持是我最大的动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

装B且挨揍の

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值