Day73 | 灵神 | 二分查找 最大合金数

Day73 | 灵神 | 二分查找 最大合金数

笔者的个人博客网站:标签: 二分查找 | Darlingの妙妙屋

2861.最大合金数

2861. 最大合金数 - 力扣(LeetCode)

注:笔者用的是左闭右开区间

思路:

还是老套路,先看二分的是什么,这道题求的是最大合金数,那么二分的就是合金数,而不是其他的东西

看看单调性,如果合金的数量越大,消耗的钱数就越多,budget就余额不够用,我们就可以找到最大值

再看二分区间,即合金数的取值范围

假设一个金属所需要的所有材料都是1,即comp数组全是1,花费cost也全是1,那最大值就是min(stock)+budget

取到最大值的情况就是,一个合金只需要一个金属并且花费也是1,这时候可以取到最大值

也可以是,最小的那个stock那个材料花费是1,所需也是1,但是其他的stock的值全都大于最小的那个stock+budget,即可以把min(stock)+budget给用完

可能的疑惑:为什么最大值是min(stock)也不是max呢?

短板效应,我们拥有的最小的stock才是限制我们的能制作的合金数量的关键

看完二分区间再来看看判断条件,即check函数该怎么写,这个也是最难的部分

我们二分的是合金数量,那么我们的mid自然就是合金数量,而我们的check函数判断的就是有budget这个预算和stock即我们拥有的金属这两个条件下,可不可以合成mid这么多的数量,如果可以合成,那么说明mid符合条件,我们可以继续往大的放大mid,即l=mid+1,合成不了mid这么多,那就说明mid大了,要往小的走

那么我们如何判断是否可以合成mid那么多的合金呢?

要合成mid数量的合金,我们每个金属需要的量是nums=comp[i]*mid,这是每个金属需要的数量

而如果nums<=stock[i],那说明我们本身就有那么多的i种金属,那就不需要买了

如果nums>stock[i],那说明我们本身没那么多,那就得补足剩下的 即 买(nums-stock[i])个该类金属

花费(nums-stock[i])*cost[i]

如果补足所有金属一共花费的钱比我们的预算多,那就合成不了mid个合金,返回false,如果少的话那就可以合成,返回true.

完整代码:

注:防止溢出需要用long lonng

class Solution {
public:
    //这种的 mid,budget,costs都得是longlong
    bool check(vector<int>& v,vector<int>& stock,vector<int>&cost,long long mid,long long budget)
    {
        //在v的条件下最多可以制造多少合金
        for(int i=0;i<stock.size();i++)
        {
            if(stock[i]<mid*v[i])
            {
                long long costs=(mid*v[i]-stock[i])*cost[i];
                budget-=costs;
            }
        }
        return budget>=0;
    }
    /*
    //这种写法budget不需要是longlong
    bool check(vector<int>& v,vector<int>& stock,vector<int>&cost,long long mid,int budget)
    {
        //在v的条件下最多可以制造多少合金
        long long costs=0;
        for(int i=0;i<stock.size();i++)
        {
            if(stock[i]<mid*v[i])
            {
                costs+=(long long)(mid*v[i]-stock[i])*cost[i];
                if(costs>budget)
                    return false;
            }
        }
        return true;
    }*/
    int maxNumberOfAlloys(int n, int k, int budget, vector<vector<int>>& composition, vector<int>& stock, vector<int>& cost) 
    {
        int res=0;
        for(auto v:composition)
        {
            int l=0,r=ranges::min(stock)+budget+1;
            while(l<r)
            {
                int mid=l+(r-l)/2;
                if(check(v,stock,cost,mid,budget))
                    l=mid+1;
                else
                    r=mid;
            }
            res=max(res,l-1);
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值