1300. 转变数组后最接近目标值的数组和
给你一个整数数组 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
原站题解
golang 解法, 执行用时: 12 ms, 内存消耗: 5.2 MB, 提交时间: 2023-09-22 10:18:43
// 枚举 + 二分 func findBestValue1(arr []int, target int) int { sort.Ints(arr) n := len(arr) prefix := make([]int, n + 1) for i := 1; i <= n; i++ { prefix[i] = prefix[i-1] + arr[i-1] } r := arr[n-1] ans, diff := 0, target for i := 1; i <= r; i++ { index := sort.SearchInts(arr, i) if index < 0 { index = -index - 1 } cur := prefix[index] + (n - index) * i if abs(cur - target) < diff { ans = i diff = abs(cur - target) } } return ans } func findBestValue(arr []int, target int) int { sort.Ints(arr) n := len(arr) prefix := make([]int, n + 1) for i := 1; i <= n; i++ { prefix[i] = prefix[i-1] + arr[i-1] } l, r, ans := 0, arr[n-1], -1 for l <= r { mid := (l + r) / 2 index := sort.SearchInts(arr, mid) if index < 0 { index = -1 * index - 1 } cur := prefix[index] + (n - index) * mid if cur <= target { ans = mid l = mid + 1 } else { r = mid - 1 } } chooseSmall := check(arr, ans) chooseBig := check(arr, ans + 1) if abs(chooseSmall - target) > abs(chooseBig - target) { ans++ } return ans } func check(arr []int, x int) int { ret := 0 for _, num := range arr { ret += min(num, x) } return ret } func min(x, y int) int { if x < y { return x } return y } func abs(x int) int { if x < 0 { return -1 * x } return x }
java 解法, 执行用时: 37 ms, 内存消耗: 42 MB, 提交时间: 2023-09-22 10:17:44
class Solution { public int findBestValue(int[] arr, int target) { Arrays.sort(arr); int n = arr.length; int[] prefix = new int[n + 1]; for (int i = 1; i <= n; ++i) { prefix[i] = prefix[i - 1] + arr[i - 1]; } int r = arr[n - 1]; int ans = 0, diff = target; for (int i = 1; i <= r; ++i) { int index = Arrays.binarySearch(arr, i); if (index < 0) { index = -index - 1; } int cur = prefix[index] + (n - index) * i; if (Math.abs(cur - target) < diff) { ans = i; diff = Math.abs(cur - target); } } return ans; } // 双重二分 public int findBestValue2(int[] arr, int target) { Arrays.sort(arr); int n = arr.length; int[] prefix = new int[n + 1]; for (int i = 1; i <= n; ++i) { prefix[i] = prefix[i - 1] + arr[i - 1]; } int l = 0, r = arr[n - 1], ans = -1; while (l <= r) { int mid = (l + r) / 2; int index = Arrays.binarySearch(arr, mid); if (index < 0) { index = -index - 1; } int cur = prefix[index] + (n - index) * mid; if (cur <= target) { ans = mid; l = mid + 1; } else { r = mid - 1; } } int chooseSmall = check(arr, ans); int chooseBig = check(arr, ans + 1); return Math.abs(chooseSmall - target) <= Math.abs(chooseBig - target) ? ans : ans + 1; } public int check(int[] arr, int x) { int ret = 0; for (int num : arr) { ret += Math.min(num, x); } return ret; } }
python3 解法, 执行用时: 448 ms, 内存消耗: 17.1 MB, 提交时间: 2023-09-22 10:16:59
class Solution: def findBestValue(self, arr: List[int], target: int) -> int: arr.sort() n = len(arr) prefix = [0] for num in arr: prefix.append(prefix[-1] + num) r, ans, diff = max(arr), 0, target for i in range(1, r + 1): it = bisect.bisect_left(arr, i) cur = prefix[it] + (n - it) * i if abs(cur - target) < diff: ans, diff = i, abs(cur - target) return ans def findBestValue2(self, arr: List[int], target: int) -> int: arr.sort() n = len(arr) prefix = [0] for num in arr: prefix.append(prefix[-1] + num) l, r, ans = 0, max(arr), -1 while l <= r: mid = (l + r) // 2 it = bisect.bisect_left(arr, mid) cur = prefix[it] + (n - it) * mid if cur <= target: ans = mid l = mid + 1 else: r = mid - 1 def check(x): return sum(x if num >= x else num for num in arr) choose_small = check(ans) choose_big = check(ans + 1) return ans if abs(choose_small - target) <= abs(choose_big - target) else ans + 1
cpp 解法, 执行用时: 100 ms, 内存消耗: 12.7 MB, 提交时间: 2023-09-22 10:16:27
class Solution { public: // 枚举 + 二分 int findBestValue(vector<int>& arr, int target) { sort(arr.begin(), arr.end()); int n = arr.size(); vector<int> prefix(n + 1); for (int i = 1; i <= n; ++i) { prefix[i] = prefix[i - 1] + arr[i - 1]; } int r = *max_element(arr.begin(), arr.end()); int ans = 0, diff = target; for (int i = 1; i <= r; ++i) { auto iter = lower_bound(arr.begin(), arr.end(), i); int cur = prefix[iter - arr.begin()] + (arr.end() - iter) * i; if (abs(cur - target) < diff) { ans = i; diff = abs(cur - target); } } return ans; } int check(const vector<int>& arr, int x) { int ret = 0; for (const int& num: arr) { ret += (num >= x ? x : num); } return ret; } // 双重二分查找 int findBestValue2(vector<int>& arr, int target) { sort(arr.begin(), arr.end()); int n = arr.size(); vector<int> prefix(n + 1); for (int i = 1; i <= n; ++i) { prefix[i] = prefix[i - 1] + arr[i - 1]; } int l = 0, r = *max_element(arr.begin(), arr.end()), ans = -1; while (l <= r) { int mid = (l + r) / 2; auto iter = lower_bound(arr.begin(), arr.end(), mid); int cur = prefix[iter - arr.begin()] + (arr.end() - iter) * mid; if (cur <= target) { ans = mid; l = mid + 1; } else { r = mid - 1; } } int choose_small = check(arr, ans); int choose_big = check(arr, ans + 1); return abs(choose_small - target) <= abs(choose_big - target) ? ans : ans + 1; } };
c 解法, 执行用时: 12 ms, 内存消耗: 7.1 MB, 提交时间: 2023-09-22 10:14:24
int cmp(const void* c1, const void* c2) { return *(int*)c1 - *(int*)c2; } int findBestValue(int* arr, int arrSize, int target){ if (arr == NULL) { return 0; } qsort(arr, arrSize, sizeof(int), cmp); int sum = 0; for (int i = 0; i < arrSize; i++) { int x = (target - sum) / (arrSize - i); if (x < arr[i]) { double t = ((double)(target - sum))/(arrSize - i); if (t - x > 0.5) { return x + 1; } else { return x; } } sum += arr[i]; } return arr[arrSize - 1]; }
java 解法, 执行用时: 1 ms, 内存消耗: 42.1 MB, 提交时间: 2023-09-22 10:13:35
class Solution { public int findBestValue(int[] arr, int target) { int big = 0; int sum = 0; for (int i : arr) { sum += i; big = big > i ? big : i; } if(sum <= target) return big; int ans = target / arr.length; sum = getSum(arr, ans); while(sum < target) { int sumn = getSum(arr, ans + 1); if(sumn >= target) return target - sum <= sumn - target ? ans : ans + 1; sum = sumn; ans++; } return 0; } public int getSum(int[] arr, int value) { int sum = 0; for (int i : arr) sum += i < value ? i : value; return sum; } }
python3 解法, 执行用时: 48 ms, 内存消耗: 17.2 MB, 提交时间: 2023-09-22 10:12:59
class Solution: # 直接暴力 def findBestValue(self, arr: List[int], target: int) -> int: summ = sum(arr) if summ <= target: return max(arr) l = len(arr) val = target // l summ, last = 0, 0 while summ < target: last = summ summ = 0 for i in range(l): summ += arr[i] if val > arr[i] else val val += 1 return val-2 if abs(target-summ) >= abs(target-last) else val-1 # 二分 def findBestValue2(self, arr: List[int], target: int) -> int: if sum(arr)<=target: return max(arr) l = len(arr) left,right = target//l,min(max(arr),target) while left<right: mid = (left+right)//2 summ = 0 for v in arr: summ +=min(v,mid) if target<summ: right = mid-1 else: left = mid+1 summ,sumright,sumleft= 0,0,0 #二分法停止时有可能在target的左边,也有可能在右边,因此,比较相邻的三个和 for v in arr: summ +=min(v,left) sumright +=min(v,left+1) sumleft +=min(v,left-1) if abs(target-sumright)>=abs(target-summ): return left if abs(target-summ)<abs(target-sumleft) else left-1 else: return left+1