把数组值一部分变大最接近目标值的值

1、描述

给你一个整数数组 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

来源:力扣(LeetCode)
链接
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2、关键字

数组、分析之后 上下界

3、思路

目标有边界,当value等于数组中最大的数时,value再增加已经没有意思,下边界是0,因为如果是负数,所有都变成负数之后,与target的差值只会越来越大,所以value在范围内取得,思路一,枚举,思路二:二分,就在下界和上界之间二分查找,
指定一个mid值之后,
1、就遍历数组计算此时的和,与target作比较,决定后面往哪个方向二分,
2、把和写成子函数的形式调用,更方便读懂,

4、notes

二分的框架

少用全局变量
如果多次用到就用变量存起来,如那个调回来的和

5、复杂度

时间:O(NlogN),第一个N是调用求和,logN是二分查找
空间:O(1)计算量大,有循环,但是并不需要存很多东西,就存几个变量而已

6、code

class Solution {
public:  // 数组、
    int sumArr(vector<int>& arr,int midd)  //把每次的一个中值,y要求的和用函数写出来
    {
        int sum=0;  // 这里的初始化很必要,不初始化就是过不去,
        for(auto val:arr)
        {
            sum += val<midd ? val : midd;
        }
        return sum;
    }
};

    int findBestValue(vector<int>& arr, int target) {       
        int n=arr.size();
        int left=0;
        int right=0;
        for(auto x:arr)  right=max(right,x);      
        
        int tarVal=INT_MAX;   // 差值
        int res=left;
        while(left<=right)
        {
            int mid=left+(right-left)/2;
            int val=sumArr(arr,mid);  // 当前mid下,求出来的一个和,因为后边几次用到,s故用变量存起来
            if(tarVal > abs(val-target))  // 依次缩小差值
            {
                tarVal=abs(val-target);
                res=mid;
            }
            if(tarVal==abs(val-target) && res> mid)  res=mid;
            if(val<target)  // 和小,往右边找
            {
                left=mid+1;
            }
            else if(val>target)  // 和大,往左边找,
            {
                right=mid-1;
            }
            else  // 相等时候直接返回结果
            return mid;
        }
        return res;

    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值