Problem
Given an integer array arr and a target value target, return the integer value such that when we change all the integers larger than value in the given array to be equal to value, the sum of the array gets as close as possible (in absolute difference) to target.
In case of a tie, return the minimum such integer.
Notice that the answer is not neccesarilly a number from arr.
Example1
Input: arr = [4,9,3], target = 10
Output: 3
Explanation: When using 3 arr converts to [3, 3, 3] which sums 9 and that’s the optimal answer.
Example2
Input: arr = [2,3,5], target = 10
Output: 5
Example3
Input: arr = [60864,25176,27249,21296,20204], target = 56803
Output: 11361
Solution
三分查找
class Solution {
public:
int findBestValue(vector<int>& arr, int target) {
int max_ele = *std::max_element(arr.begin(),arr.end());
return ternarySearch(arr,0,max_ele,target);
}
int diffSum(vector<int>& arr,int val,int target)
{
int sum = 0;
for(auto num:arr)
{
if(num > val)
sum += val;
else
sum += num;
}
return abs(target-sum);
}
int ternarySearch(vector<int>& arr,int l, int r,int target) {
while (l < r)
{
int m1 = l + (r - l) / 3;
int m2 = r - (r - l) / 3;
int diffSum1 = diffSum(arr,m1,target);
int diffSum2 = diffSum(arr,m2,target);
if(l + 2 == r) //特判,如果只有三個數字了,找到最小的那一個
{
int diffSum3 = diffSum(arr,l+1,target);
if(diffSum1<=diffSum2 && diffSum1<=diffSum3)
return l;
else if(diffSum3< diffSum1 && diffSum3 <= diffSum2)
return l+1;
else if(diffSum2 < diffSum1 && diffSum2 < diffSum3)
return r;
}
if (diffSum(arr,m1,target) >= diffSum(arr,m2,target)) //說明最小值在靠近m2的那一側,即區間[m1,r]
{
l = m1;
}
else //說明最小值在靠近m1的那一側,即區間[l,m2]
{
r = m2;
}
}
return l;
}
};
Ref
https://www.jianshu.com/p/60d8c3e576d7