leetcode1300. 转变数组后最接近目标值的数组和/二分法

题目

给你一个整数数组 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 <= arr.length <= 10^4
  • 1 <= arr[i], target <= 10^5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-mutated-array-closest-to-target
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

基本思想:二分法

  • 对目标值进行二分
  • 如果取中间值,对应的数组的和比目标值大或者等于(因为题目要求要找所有方案中最小的),那么在[left,mid]中寻找,否则在[mid,right]中找。因为mid也有可能成为最终的结果,所以在取区间的时候不进行-1或者+1操作
  • 循环的条件是[left,right]中至少有三个数,对于最终的结果在left,right中分别判断
  • 注意:当数组中的最大值不超过mid时,需要将区间缩放到[left,mid]
class Solution {
public:
    int findBestValue(vector<int>& arr, int target) {
        //二分法
        int l = 0, r = target, mid = (r - l) / 2 + l, cur;
        int m = *max_element(arr.begin(), arr.end());
        
        while(r - l > 1){
            mid = (r - l) / 2 + l;
            cur = 0;
            for(auto t : arr)
                cur += (t > mid) ? mid : t;
            if(m <= mid){
                r = mid;
                continue;
            }
            if(cur >= target){
                r = mid;
            }
            else if(cur < target){
                l = mid;
            }            
        }
        mid = l;
        cur = 0;
        for(auto t : arr)
            cur += (t > mid) ? mid : t;
        int div1 = abs(cur - target);
        mid = r;
        cur = 0;
        for(auto t : arr)
            cur += (t > mid) ? mid : t;
        int div2 = abs(cur - target);
        return (div1 > div2)? r : l;
    }
};

说明:

  • 对于上述二分的范围,可以直接对数组的最大值进行二分
  • 对于每次循环求和,可以先将数组排序,借助前缀和的思想来求当前情况下的和。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章