[LeetCode]1300.转变数组后最接近目标值的数组和

在这里插入图片描述

解法

由于arr[i]的范围是 [ 1 , 1 0 5 ] [1,10^5] [1,105]所以可以使用枚举法来寻找合适的value值,那么就需要确定value的上下限。

  • 当value=0时数组内元数都小于value,如果value继续减小,则数组元素之和也不会改变,所以value下限为0
  • 当value>=数组内元素最大值时,数组元素之和也不会改变所以value上限为数组元素最大值。

确定value上下限后就可以枚举,当value=x时需要找出arr中刚好比x大的值a[i],arr中小于x的部分不变,大于等于x的值变为x,数组之和公式为:

a [ 0 ] + . . . + a [ i − 1 ] + ( n − i ) ∗ x a[0]+...+a[i-1]+(n-i)*x a[0]+...+a[i1]+(ni)x
可以预处理数组的前缀和,这样数组求和的时间复杂度降到o(1),将数组和与target比较不断更新即可。

class Solution {
    public int findBestValue(int[] arr, int target) {
        Arrays.sort(arr);//二分查找之前对数组进行排序
        int n = arr.length;
        int[] prefix = new int[n+1];
        //提前计算好前缀之和存放到数组中
        for(int i = 1; i <= n; i++){
            prefix[i] = prefix[i - 1] + arr[i - 1];
        }
        int ans = 0;
        int r = arr[n-1];//value的上限
        int diff = target;
        for(int value = 1; value <= r; value++){//枚举查询arr中刚好大于value的值
            int index = Arrays.binarySearch(arr,value);
            if(index < 0){//搜索值不是数组元数,且大于数组内元数返回-(length + 1);
            //不是数组元数,且小于数组内元数返回-1;在数组范围内则得到“-插入点索引值”
                index = -index - 1;
            }
            int cur = prefix[index] + value * (n - index);
            if(Math.abs(cur - target) < diff){
                ans = value;
                diff = Math.abs(cur - target);
            }
        }
        return ans;
    }
}

binarySearch(Object[] a, Object key)

a: 要搜索的数组

key:要搜索的值

如果key在数组中,则返回搜索值的索引;否则返回-1或“-”(插入点)。插入点是索引键将要插入数组的那一点,即第一个大于该键的元素的索引。

技巧:

  1. 搜索值不是数组元素,且在数组范围内,从1开始计数,得“ - 插入点索引值”;

  2. 搜索值是数组元素,从0开始计数,得搜索值的索引值;

  3. 搜索值不是数组元素,且大于数组内元素,索引值为 – (length + 1);

  4. 搜索值不是数组元素,且小于数组内元素,索引值为 – 1。

posted @ 2020-06-15 10:01  消灭猕猴桃  阅读(63)  评论(0编辑  收藏  举报