转变数组后最接近目标值的数组和
难度:
标签:
题目描述
代码结果
运行时间: 34 ms, 内存: 17.0 MB
/*
* Approach:
* 1. Sort the array.
* 2. Calculate the prefix sum.
* 3. Use binary search to find the value which when replacing all elements greater than it minimizes the difference with the target.
* Note: Using Java Streams to find the prefix sum and binary search.
*/
import java.util.Arrays;
public class Solution {
public int findBestValue(int[] arr, int target) {
Arrays.sort(arr);
int n = arr.length;
int[] prefix = new int[n + 1];
Arrays.parallelPrefix(arr, (x, y) -> x + y);
for (int i = 0; i < n; ++i) {
prefix[i + 1] = prefix[i] + arr[i];
}
int l = 0, r = arr[n - 1];
int ans = 0, diff = target;
while (l <= r) {
int mid = (l + r) / 2;
int it = Arrays.binarySearch(arr, mid);
if (it < 0) it = -it - 1;
int cur = prefix[it] + (n - it) * mid;
if (Math.abs(cur - target) < diff) {
ans = mid;
diff = Math.abs(cur - target);
} else if (Math.abs(cur - target) == diff) {
ans = Math.min(ans, mid);
}
if (cur < target) {
l = mid + 1;
} else {
r = mid - 1;
}
}
return ans;
}
}
解释
方法:
这个题解采用了贪心算法的思路。首先计算数组的和,如果和小于等于目标值,则直接返回数组中的最大值。如果和大于目标值,那么就需要找到一个值value,使得将数组中所有大于value的值变成value后,数组的和最接近目标值。初始时,value设为target除以数组长度,然后逐渐增加value,每次增加后重新计算数组的和,直到和大于等于目标值为止。最后,比较value和value-1哪个使得数组和更接近目标值,返回较优的那个。
时间复杂度:
O(n^2)
空间复杂度:
O(1)
代码细节讲解
🦆
为什么题解中选择初始的 value 为 target 除以数组长度,这种设定有什么数学依据或者直观解释吗?
▷🦆
题解中提到在 value 增加的过程中会重新计算数组的和,这种方法是否最有效率?还有没有其他可能的改进方法来减少计算次数?
▷🦆
在比较 value 和 value-1 哪个更接近目标值时,为什么返回 value-2 或 val-1,这里的逻辑是否有误,应该是比较哪两个值?
▷🦆
题解中没有明确如何处理有多个 value 使得和最接近 target 的情况,实际算法是如何确保返回的是最小的那个 value?
▷