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

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

这个题是昨天的每日一题,昨天太忙了,没来得及写完。但是有了思想,本地上跑了几次发现跑出来的答案又误差就溜掉了。
今天有空了就来填一下坑。

class Solution {
    public int findBestValue(int[] arr, int target) {
        //先进行排序,取得搜索的边界,边界就是0到数组元素中的最大值
        Arrays.sort(arr);
        //这个前缀和数组还是非常重要的,这个长度一定要多一,否则就会像之前做的一样搜出来的值不对。
        int[] prefixSum = new int[arr.length + 1];
        //计算前缀和数组
        for(int i = 1; i <= arr.length; i++){
            prefixSum[i] = prefixSum[i-1] + arr[i-1];
        }
        //记录当前与目标值最短的距离
        int minDistance = target;
        //记录答案
        int ans = 0;
        for(int i = 0; i <= arr[arr.length-1]; i++){
            //首先二分搜索我们取的值在arr数组中的位置。
            int cur = helper(arr,i);
            //利用前缀和数组计算和。
            // 比如说我们有2,3,5 我们取3,题目的意思是大于3的都要变成3,我们上面取的值就是1,那么我们这里就是取前缀和数组下标为1的值
            //当然这个会有偏移,实际上是原来的0号数据。然后加上(3-1) * 3,这个的意思是我们数组中的3,5都要变成3。
            int sum = prefixSum[cur] + (arr.length - cur) * i;
            //判断距离差的大小。
            if(Math.abs(target - sum) < minDistance){
                ans = i;
                minDistance = Math.abs(target - sum);
            }
        }
        return ans;
    }

    //二分查找模板,很容易 
    public int helper(int[] arr,  int target){
        int left = 0;
        int right = arr.length-1;
        while(left < right){
            int mid = left + (right - left)/2;
            if(arr[mid] >= target){
                right = mid;
            }else{
                left = mid + 1;
            }
        }
        return right;
    }
}

有个很奇怪的地方,自己写的反而不如直接调用系统库中的Arrays.binarySearch()方法快。醉了
说起二分查找 ,这个题的确有点像我之前做过的二分查找变种题,具体请看这里
不过这个题还有更快的方法,就是双重二分查找,我昨天第一次写的时候就是双重二分查找,对于我们寻找的ans进行二分查找,然后在循环体内查找当前可能的答案在arr数组中的位置,等到有时间了我再来补上这个坑。

posted @ 2020-06-15 11:20  ZJPang  阅读(130)  评论(0编辑  收藏  举报