Leetcode 1300.轉變數組後最接近目標值的數組和
1 題目描述(Leetcode題目鏈接)
給你一個整數數組 arr 和一個目標值 target ,請你返回一個整數 value ,使得將數組中所有大於 value 的值變成 value 後,數組的和最接近 target (最接近表示兩者之差的絕對值最小)。
如果有多種使得和最接近 target 的方案,請你返回這些整數中的最小值。
請注意,答案不一定是 arr 中的數字。
輸入:arr = [4,9,3], target = 10
輸出:3
解釋:當選擇 value 爲 3 時,數組會變成 [3, 3, 3],和爲 9 ,這是最接近 target 的方案。
輸入:arr = [2,3,5], target = 10
輸出:5
輸入:arr = [60864,25176,27249,21296,20204], target = 56803
輸出:11361
提示:
- 1 <= arr.length <= 10^4
- 1 <= arr[i], target <= 10^5
2 題解
本題使用前綴和+二分搜索,先將數組排序並記錄前綴和,規定二分查找的左邊界爲,右邊界爲數組最大值,二分查找要替換的值。我們需要計算替換值後數組的和,因此我們可以再使用一個二分查找在數組中搜索最後一個小於替換值的元素的下標,這樣替換後數組的和就可以計算爲:
其中爲替換值,爲最後一個小於替換值的元素的下標,爲數組長度。
另外,這裏查找替換值的二分查找退出條件使用的是,最後要判斷和到底哪一個是正確的返回值。
class Solution:
def findBestValue(self, arr: List[int], target: int) -> int:
arr.sort()
n = len(arr)
prefix = [0]
s = 0
for i in range(n):
s += arr[i]
prefix.append(s)
i, j = 0, arr[-1]
while i < j - 1:
mid = (i + j) // 2
index = bisect.bisect_left(arr, mid)
s = prefix[index] + mid*(n - index)
if s == target:
return mid
elif s > target:
j = mid
else:
i = mid
a = bisect.bisect_left(arr, i)
a = prefix[a] + i*(n - a)
b = bisect.bisect_left(arr, j)
b = prefix[b] + j*(n - b)
return i if abs(a - target) <= abs(b - target) else j