二分查找中取满足条件值中的最小值(不连续)

给你一个整数数组 arr 和一个目标值 target ,请你返回一个整数 value ,使得将数组中所有大于 value 的值变成 value 后,数组的和最接近  target (最接近表示两者之差的绝对值最小)。

如果有多种使得和最接近 target 的方案,请你返回这些整数中的最小值。

请注意,答案不一定是 arr 中的数字。

示例 1:

输入:arr = [4,9,3], target = 10
输出:3
解释:当选择 value 为 3 时,数组会变成 [3, 3, 3],和为 9 ,这是最接近 target 的方案。
示例 2:

输入:arr = [2,3,5], target = 10
输出:5
示例 3:

输入:arr = [60864,25176,27249,21296,20204], target = 56803
输出:11361
 

提示:

1 <= arr.length <= 10^4
1 <= arr[i], target <= 10^5

 https://leetcode.cn/problems/sum-of-mutated-array-closest-to-target/

利用二分查找可以得到满足条件的值,但是不满足多种方案去最小值的要求,这里需要在二分中寻找。

int findBestValue(vector<int>& arr, int target) {
        sort(arr.begin(),arr.end());
        vector<int>presum(arr.size()+5);
        presum[0]=0;
        for(int i=1;i<=arr.size();i++)
        {
            presum[i]=presum[i-1]+arr[i-1];//前缀和以1下标为起点,防止溢出讨论
        }
        int l=1,r=*max_element(arr.begin(),arr.end()),ans=INT_MAX,index=0;
        while(l<r)
        {
            int mid=(l+r)/2;
            int k=upper_bound(arr.begin(),arr.end(),mid)-arr.begin();//大于mid点的下标
            int cur=presum[k]+mid*(arr.size()-k);
            if(cur<target)
            {
                int x=upper_bound(arr.begin(),arr.end(),mid+1)-arr.begin();//大于mid+1
                int y=presum[x]+(mid+1)*(arr.size()-x);
                if(abs(cur-target)<=ans)
                {
                    if(abs(cur-target)<ans)
                    {
                        ans=abs(cur-target);index=mid;
                    }
                    else if(abs(cur-target)==ans&&mid<index)index=mid;
                }                            //在mid和mid+1中寻找
                if(abs(y-target)<=ans)
                {
                    if(abs(y-target)<ans)
                    {
                        ans=abs(y-target);index=mid+1;
                    }
                    else if(abs(y-target)==ans&&mid+1<index)index=mid+1;
                }
                l=mid+1;
            }
            else r=mid;
        }
        return index;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

装B且挨揍の

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

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

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

打赏作者

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

抵扣说明:

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

余额充值