题目
给你一个整数数组 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-mutated-array-closest-to-target
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
基本思想:二分法
- 对目标值进行二分
- 如果取中间值,对应的数组的和比目标值大或者等于(因为题目要求要找所有方案中最小的),那么在[left,mid]中寻找,否则在[mid,right]中找。因为mid也有可能成为最终的结果,所以在取区间的时候不进行-1或者+1操作
- 循环的条件是[left,right]中至少有三个数,对于最终的结果在left,right中分别判断
- 注意:当数组中的最大值不超过mid时,需要将区间缩放到[left,mid]
class Solution {
public:
int findBestValue(vector<int>& arr, int target) {
//二分法
int l = 0, r = target, mid = (r - l) / 2 + l, cur;
int m = *max_element(arr.begin(), arr.end());
while(r - l > 1){
mid = (r - l) / 2 + l;
cur = 0;
for(auto t : arr)
cur += (t > mid) ? mid : t;
if(m <= mid){
r = mid;
continue;
}
if(cur >= target){
r = mid;
}
else if(cur < target){
l = mid;
}
}
mid = l;
cur = 0;
for(auto t : arr)
cur += (t > mid) ? mid : t;
int div1 = abs(cur - target);
mid = r;
cur = 0;
for(auto t : arr)
cur += (t > mid) ? mid : t;
int div2 = abs(cur - target);
return (div1 > div2)? r : l;
}
};
说明:
- 对于上述二分的范围,可以直接对数组的最大值进行二分
- 对于每次循环求和,可以先将数组排序,借助前缀和的思想来求当前情况下的和。