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;
}