每日一道算法题LeetCode1300:Sum of Mutated Array Closest to Target(转变数组后最接近目标值的数组和)

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

  • 题目
  • 分析
  • 题解
    • 排序后遍历
    • 枚举+二分查找
  • 总结

题目

题目:给你一个整数数组 arr 和一个目标值 target ,请你返回一个整数 value ,使得将数组中所有大于 value 的值变成 value 后,数组的和最接近 target (最接近表示两者之差的绝对值最小)。

如果有多种使得和最接近 target 的方案,请你返回这些整数中的最小值。

请注意,答案不一定是 arr 中的数字。

题目链接: link.

分析

提供一个数组,返回一个值res,使当把数组里的每一个大于res的值变为res后,数组的和接近target。这里要注意数组的和是左接近还是右接近,因为需要的是最接近target的最小值。

题解

排序后遍历

这个解法就是暴力法,但是效果很好,本题官方给的标签是二分法,但是实际写下来完全没有必要二分,先将数组排序,然后依次往后遍历,找到最小的一个值返回即可,时间空间并不复杂。代码如下(java):

	public static int findBestValue(int[] arr, int target){
        Arrays.sort(arr);   // 排序
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            int temp = (target-sum)/(arr.length-i);
            if(temp <= arr[i]){ // 检验结果是否小于下一个数
            	// 判断左接近还是右接近
            	// 当left = 0.5时说明两边一样接近,此时取较小值
            	// 小于0.5 左边更接近
            	// 大于0.5右边更接近,加一即可
                double left = (target*1.0 - sum)/(arr.length-i) - temp; 
                if(left>0.5)    return temp+1;
                else return temp;
            }
            sum += arr[i];   // 更新sum
        }
        return arr[arr.length-1];  // 循环完没有找到value,返回最大值
    }

枚举+二分查找

这是官方给出的题解,从0到数组最大值一个一个枚举,然后使用二分法找到数组里大于该数的第一个数下标。官方代码如下(别问为什么是官方题解):

	public static int findBestValue(int[] arr, int target) {
        Arrays.sort(arr);
        int n = arr.length;
        int[] prefix = new int[n + 1];    // 记录前n个值的和,减少求和时间
        for (int i = 1; i <= n; ++i) {
            prefix[i] = prefix[i - 1] + arr[i - 1];
        }
        int r = arr[n - 1];
        int ans = 0, diff = target;
        for (int i = 1; i <= r; ++i) {
        // binarySearch返回值:
        // 如果key在数组中,则返回搜索值的索引;否则返回-1或“-”(插入点)
        // 。插入点是索引键将要插入数组的那一点,即第一个大于该键的元素的索引。
            int index = Arrays.binarySearch(arr, i);    
            if (index < 0) {
                index = -index - 1;
            }
            int cur = prefix[index] + (n - index) * i;
            if (Math.abs(cur - target) < diff) {   // 找到与target差最小的值
                ans = i;
                diff = Math.abs(cur - target);
            }
        }
        return ans;
    }

总结

个人感觉这个题不难,但是不知道为什么是中等难度,可能是我想的太简单了吧,hhh。谢谢阅读!

你可能感兴趣的:(算法,java,数据结构,leetcode)