題目
給你一個整數數組 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;
}
};
說明:
- 對於上述二分的範圍,可以直接對數組的最大值進行二分
- 對於每次循環求和,可以先將數組排序,藉助前綴和的思想來求當前情況下的和。