「这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战」
题意描述
给你一个整数数组 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
分析
- 我们首先去读懂题意,可以分析出结果的取值范围应当是0-max
- 而0-max对应区间的sum又是是单调递增的,所以我们可以分析出二分才是这题的核心
- 那么我们要想确定差的绝对值最小,我们就可以先求出比target大的最小值,那么结果必出在最小值和最小值-1,两个比较一下,结果就出来了。
var findBestValue = function(arr, target) {
arr.sort((a,b)=>a-b)
let sum=0
for(let i=0;i<arr.length;i++){
sum+=+arr[i]
const total=sum+arr[i]*(arr.length-1-i)
if(total>target){
if(i===0){
return Math.round(target/arr.length)
}else{
const preTotal = sum - arr[i] + arr[i - 1] * (arr.length - i)
const nowAverage = Math.ceil((target - sum + arr[i]) / (arr.length - i))
if (nowAverage < arr[i]) {
if (
Math.abs(sum - arr[i] + nowAverage * (arr.length - i) - target) <
Math.abs(
sum - arr[i] + (nowAverage - 1) * (arr.length - i) - target
)
) {
return nowAverage
} else {
return nowAverage - 1
}
}
if(Math.abs(total-target)>Math.abs(preTotal-target)){
return arr[i]
}else{
return arr[i-1]
}
}
}else {
if (i === arr.length - 1) {
return arr[i]
}
}
}
};
当然我尝试了一下,纯粹的暴力方法这题也能卡过去。我们都知道当arr中数据都替换成的最大值时都小于target是返回最大值,那么循环arr的平均值到arr的最大值分别计算替换后数组的和,如果小于平均数的和+指针之前的数的和(大于平均数的地方)我们只要计算和与target之前的差,每次比较上一次差与这次的大小,取最小值,就可以得到结果
var findBestValue = function(arr, target) {
let sorted = arr.sort((x,y)=>x-y);
let sums_cur = sorted[0];
let sums_pre = -1;
let value = Math.round(target / sorted.length);
value = Math.min(value, sorted[0]);
for (let i = 1; i < sorted.length; i ++){
sums_pre = sums_cur;
sums_cur = sums_pre + sorted[i];
let new_value = Math.round((target - sums_pre) / (sorted.length - i) - 0.000001);
new_value = Math.min(new_value, sorted[i]);
if (sorted[i-1] > new_value){
break;
}
value = new_value;
}
return value;
};
感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。
写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤