🌈【LeetCode.目标数组和】- JavaScript =>二分+暴力

426 阅读2分钟

「这是我参与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;
};

感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。

写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤