【问题描述】[中等]
给你一个整数数组 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
示例 3:输入:arr = [60864,25176,27249,21296,20204], target = 56803
输出:11361
【解答思路】
1. 暴力法
时间复杂度:O(N^2) 空间复杂度:O(1)
class Solution {public int findBestValue(int[] arr, int target) {int min = Integer.MAX_VALUE;int num = target/arr.length, minIndex = num;for (int i = num; i < target; i++) {int sum = 0;for (int j = 0; j < arr.length; j++) {if (arr[j] > i) sum += i;else sum += arr[j];}if (Math.abs(target-sum) < min) {min = Math.abs(target-sum);minIndex = i;} else break;}return minIndex;}
}
2. 二分法
时间复杂度:O(NlogN) 空间复杂度:O(1)
public class Solution {public int findBestValue(int[] arr, int target) {int left = 0;int right = 0;// 注意:for (int num : arr) {right = Math.max(right, num);}while (left < right) {int mid = left + (right - left) / 2;int sum = calculateSum(arr, mid);// 计算第 1 个使得转变后数组的和大于等于 target 的阈值 thresholdif (sum < target) {// 严格小于的一定不是解left = mid + 1;} else {right = mid;}}// 比较阈值线分别定在 left - 1 和 left 的时候与 target 的接近程度int sum1 = calculateSum(arr, left - 1);int sum2 = calculateSum(arr, left);if (target - sum1 <= sum2 - target) {return left - 1;}return left;}private int calculateSum(int[] arr, int threshold) {int sum = 0;for (int num : arr) {sum += Math.min(num, threshold);}return sum;}public static void main(String[] args) {int[] arr = new int[]{2, 3, 5};int target = 11;Solution solution = new Solution();int res = solution.findBestValue(arr, target);System.out.println(res);}
}
时间复杂度:O(NlogN) 空间复杂度:O(1)
public class Solution {public int findBestValue(int[] arr, int target) {int left = 0;int right = 0;// 注意:for (int num : arr) {right = Math.max(right, num);}while (left < right) {int mid = left + (right - left + 1) / 2;int sum = calculateSum(arr, mid);// 计算最后 1 个使得转变以后数组的和小于等于 target 的阈值 thresholdif (sum > target) {// 大于等于的就不是解,threshold 太大了,下一轮搜索区间是 [left, mid - 1]right = mid - 1;} else {// 下一轮搜索区间是 [mid, right]left = mid;}}// 比较阈值线分别定在 left 和 left + 1 的时候与 target 的接近程度int sum1 = calculateSum(arr, left);int sum2 = calculateSum(arr, left + 1);// 注意:这里必须加绝对值,因为有可能出现 sum1 == sum2 < target 的情况if (Math.abs(target - sum1) <= Math.abs(sum2 - target)) {return left;}return left + 1;}private int calculateSum(int[] arr, int threshold) {int sum = 0;for (int num : arr) {sum += Math.min(num, threshold);}return sum;}public static void main(String[] args) {int[] arr = new int[]{2, 3, 5};int target = 11;Solution solution = new Solution();int res = solution.findBestValue(arr, target);System.out.println(res);}
}
【总结】
1.巧妙计算前缀和
int[] prefix = new int[n + 1];for (int i = 1; i <= n; ++i) {prefix[i] = prefix[i - 1] + arr[i - 1];}
2. binarySearch(Object[], Object key)
3.排除法二分总结
参考链接https://blog.csdn.net/dadongwudi/article/details/105345157
转载链接:https://leetcode-cn.com/problems/sum-of-mutated-array-closest-to-target/solution/er-fen-cha-zhao-by-liweiwei1419-2/
参考链接:https://leetcode-cn.com/problems/sum-of-mutated-array-closest-to-target/solution/fen-duan-zhi-hou-bao-li-cha-zhao-guan-fang-shu-ju-/