leetcode
leetcode 1051 ~ 1100
转变数组后最接近目标值的数组和

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

难度:

标签:

题目描述

代码结果

运行时间: 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 为 target 除以数组长度是基于将目标值平均分配到每个数组元素的直观想法。如果我们希望调整数组的元素,使得它们的总和尽可能接近目标值 target,那么一个理想的起点是将 target 均等地分配给每个元素,这样每个元素的目标值就是 target 除以数组长度。这不仅提供了一个合理的起始估计值,而且简化了算法的实现,因为这通常会是调整过程中的一个中间值。
🦆
题解中提到在 value 增加的过程中会重新计算数组的和,这种方法是否最有效率?还有没有其他可能的改进方法来减少计算次数?
题解中的方法通过逐步增加 value 并重新计算整个数组的和不是最高效的方法,因为每次 value 改变都需要遍历整个数组来计算新的总和。一种可能的改进方法是使用排序和前缀和。首先,对数组进行排序。然后,利用前缀和技术来快速计算在不同的 value 设置下数组的和。使用二分查找方法来确定最接近目标的 value,这样可以显著减少必要的迭代次数和总的计算量。
🦆
在比较 value 和 value-1 哪个更接近目标值时,为什么返回 value-2 或 val-1,这里的逻辑是否有误,应该是比较哪两个值?
确实存在逻辑上的疏漏。在算法中,应当比较的是在最后一次迭代中使得和刚好大于等于目标值的 value 和前一次迭代的 value-1。因此,应当比较 value-1 和 value-2 的总和与目标值的接近程度,而非直接返回 value-2 或 value-1。需要修正逻辑,以确保比较和选择是正确的。
🦆
题解中没有明确如何处理有多个 value 使得和最接近 target 的情况,实际算法是如何确保返回的是最小的那个 value?
题解中未明确说明这一点,但理想的实现应该是这样的:在确定了可能的 value 后(即值使得总和最接近目标值的两个候选值),应当选择这两者中较小的一个,如果它们导致的总和相同的话。确保返回最小的 value 可以通过在迭代过程中持续跟踪并更新当找到一个新的、更接近目标值的 value 时,只有在这个新的 value 小于或等于之前记录的相同效果的 value 时,才更新记录。

相关问题