Language Selection
Choose your preferred programming language
Problem Statement
You are given an integer array arr and an integer target. You may choose an integer value v and mutate the array as follows:
- Replace every element
xinarrwithmin(x, v).
Let S(v) be the sum of the mutated array. Your goal is to find the integer v such that S(v) is closest to target.
- If there are multiple
vvalues that produce sums equally close totarget, return the smallest suchv.
Input / Output Format
- Input:
arr: List[int],target: int - Output:
int(the chosen valuev)
Constraints
1 <= arr.length <= 10^41 <= arr[i] <= 10^51 <= target <= 10^5
Examples
Example 1
Input: arr = [4, 9, 3], target = 10
Try values:
v = 3→ mutated[3,3,3]sum = 9 (diff 1)v = 4→ mutated[4,4,3]sum = 11 (diff 1)
Both are equally close, return the smaller v.
Output: 3
Example 2
Input: arr = [2, 3, 5], target = 10
If v >= 5, array unchanged, sum = 10 exactly.
Output: 5
Example 3
Input: arr = [60864, 25176, 27249, 21296, 20204], target = 56803
The best v is the one that caps large values so the sum is near 56803. (This is a typical case where binary search is useful.)
Output: 11361
Edge-focused Example 4 (very small target)
Input: arr = [5, 6, 7], target = 1
Even with v = 0 (not allowed in constraints, but v can be 0 in the original problem; LeetCode allows v in [0, max(arr)]), sum would be 0; with v = 1, sum = 3. Closest is v = 0 if allowed; under typical LeetCode interpretation, v can be 0.
Output (LeetCode): 0
Note: LeetCode’s original problem allows
vin[0, max(arr)]. Most solutions search that range.
Approach 1: Brute Force
Algorithm Explanation
The mutated sum S(v) is monotonic non-decreasing with respect to v:
- Increasing
vcan only increase (or keep) eachmin(arr[i], v).
A brute force approach:
- Iterate
vfrom0tomax(arr). - Compute
S(v)by summingmin(x, v)for allxinarr. - Track the
vthat minimizesabs(S(v) - target), breaking ties by choosing smallerv.
This is straightforward but can be too slow when max(arr) is large (up to 1e5).
Python Implementation
from typing import List
class Solution:
def findBestValue(self, arr: List[int], target: int) -> int:
mx = max(arr)
best_v = 0
best_diff = float('inf')
for v in range(mx + 1):
s = 0
for x in arr:
s += x if x < v else v
diff = abs(s - target)
if diff < best_diff or (diff == best_diff and v < best_v):
best_diff = diff
best_v = v
return best_v
Complexity Analysis
- Let
n = len(arr),M = max(arr) - Time:
O(n * M) - Space:
O(1)
Approach 2: Optimized Solution (Binary Search + Prefix Sums)
Better Algorithm Explanation
We want the v where S(v) is closest to target. Since S(v) is monotonic, we can binary search on v.
To compute S(v) fast:
- Sort
arr. - Build prefix sums
prefix[i] = sum(arr[0..i-1]). - For a given
v, find the first indexidxwherearr[idx] > v(upper bound).- Elements before
idxremain unchanged: sum =prefix[idx] - Elements from
idxonward becomev: contribution =(n - idx) * v - So
S(v) = prefix[idx] + (n - idx) * v
- Elements before
Binary search finds the smallest v such that S(v) >= target. The best answer is either that v or v-1 (because closest could be just below the crossing point). Compare both and apply tie-breaking.
Python Implementation
from bisect import bisect_right
from typing import List
class Solution:
def findBestValue(self, arr: List[int], target: int) -> int:
arr.sort()
n = len(arr)
prefix = [0] * (n + 1)
for i, x in enumerate(arr, 1):
prefix[i] = prefix[i - 1] + x
def mutated_sum(v: int) -> int:
idx = bisect_right(arr, v) # first index with arr[idx] > v
return prefix[idx] + (n - idx) * v
lo, hi = 0, arr[-1]
while lo < hi:
mid = (lo + hi) // 2
if mutated_sum(mid) < target:
lo = mid + 1
else:
hi = mid
# lo is the smallest v with S(v) >= target
cand1 = lo
cand2 = lo - 1
def score(v: int):
return abs(mutated_sum(v) - target)
if cand2 >= 0 and score(cand2) <= score(cand1):
return cand2
return cand1
Java Implementation
import java.util.*;
class Solution {
public int findBestValue(int[] arr, int target) {
Arrays.sort(arr);
int n = arr.length;
long[] prefix = new long[n + 1];
for (int i = 0; i < n; i++) prefix[i + 1] = prefix[i] + arr[i];
java.util.function.IntToLongFunction sum = (int v) -> {
int idx = upperBound(arr, v); // first > v
return prefix[idx] + (long)(n - idx) * v;
};
int lo = 0, hi = arr[n - 1];
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (sum.applyAsLong(mid) < target) lo = mid + 1;
else hi = mid;
}
int cand1 = lo, cand2 = lo - 1;
long diff1 = Math.abs(sum.applyAsLong(cand1) - target);
long diff2 = cand2 >= 0 ? Math.abs(sum.applyAsLong(cand2) - target) : Long.MAX_VALUE;
if (diff2 <= diff1) return cand2;
return cand1;
}
private int upperBound(int[] a, int v) {
int lo = 0, hi = a.length;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] <= v) lo = mid + 1;
else hi = mid;
}
return lo;
}
}
Go Implementation
package main
import (
"sort"
)
func findBestValue(arr []int, target int) int {
sort.Ints(arr)
n := len(arr)
prefix := make([]int64, n+1)
for i := 0; i < n; i++ {
prefix[i+1] = prefix[i] + int64(arr[i])
}
mutatedSum := func(v int) int64 {
// upper bound: first index with arr[idx] > v
idx := sort.SearchInts(arr, v+1)
return prefix[idx] + int64(n-idx)*int64(v)
}
lo, hi := 0, arr[n-1]
for lo < hi {
mid := (lo + hi) / 2
if mutatedSum(mid) < int64(target) {
lo = mid + 1
} else {
hi = mid
}
}
cand1, cand2 := lo, lo-1
diff1 := abs64(mutatedSum(cand1) - int64(target))
diff2 := int64(1<<62)
if cand2 >= 0 {
diff2 = abs64(mutatedSum(cand2) - int64(target))
}
if diff2 <= diff1 {
return cand2
}
return cand1
}
func abs64(x int64) int64 {
if x < 0 {
return -x
}
return x
}
JavaScript Implementation
function findBestValue(arr, target) {
arr.sort((a, b) => a - b);
const n = arr.length;
const prefix = new Array(n + 1).fill(0);
for (let i = 0; i < n; i++) prefix[i + 1] = prefix[i] + arr[i];
function upperBound(v) {
let lo = 0, hi = n;
while (lo < hi) {
const mid = (lo + hi) >> 1;
if (arr[mid] <= v) lo = mid + 1;
else hi = mid;
}
return lo;
}
function mutatedSum(v) {
const idx = upperBound(v);
return prefix[idx] + (n - idx) * v;
}
let lo = 0, hi = arr[n - 1];
while (lo < hi) {
const mid = (lo + hi) >> 1;
if (mutatedSum(mid) < target) lo = mid + 1;
else hi = mid;
}
const cand1 = lo, cand2 = lo - 1;
const diff1 = Math.abs(mutatedSum(cand1) - target);
const diff2 = cand2 >= 0 ? Math.abs(mutatedSum(cand2) - target) : Number.POSITIVE_INFINITY;
return diff2 <= diff1 ? cand2 : cand1;
}
C# Implementation
using System;
public class Solution {
public int FindBestValue(int[] arr, int target) {
Array.Sort(arr);
int n = arr.Length;
long[] prefix = new long[n + 1];
for (int i = 0; i < n; i++) prefix[i + 1] = prefix[i] + arr[i];
long MutatedSum(int v) {
int idx = UpperBound(arr, v);
return prefix[idx] + (long)(n - idx) * v;
}
int lo = 0, hi = arr[n - 1];
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (MutatedSum(mid) < target) lo = mid + 1;
else hi = mid;
}
int cand1 = lo, cand2 = lo - 1;
long diff1 = Math.Abs(MutatedSum(cand1) - target);
long diff2 = cand2 >= 0 ? Math.Abs(MutatedSum(cand2) - target) : long.MaxValue;
return diff2 <= diff1 ? cand2 : cand1;
}
private int UpperBound(int[] a, int v) {
int lo = 0, hi = a.Length;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] <= v) lo = mid + 1;
else hi = mid;
}
return lo;
}
}
Complexity Analysis
- Sorting:
O(n log n) - Each
mutated_sum(v)query:O(log n)via upper bound - Binary search over
vin[0, max(arr)]:O(log max(arr)) - Total:
O(n log n + log(max(arr)) * log n) - Space:
O(n)for prefix sums
Key Insights
- Monotonic function:
S(v)is monotone non-decreasing, enabling binary search on the answer. - Only two candidates matter: Once you find the smallest
vwithS(v) >= target, the best answer is eithervorv-1(closest on either side of the crossing). - Prefix sums after sorting let you compute
S(v)quickly by splitting the array into:- values
<= v(unchanged) - values
> v(capped tov)
- values
Edge Cases
targetis very small (possibly smaller thanlen(arr)), pushing the bestvtoward0.targetis very large (>= sum(arr)), bestvshould bemax(arr)(no mutation needed).- Many duplicates in
arr. arrlength = 1.- Tie case where
S(v)andS(v+1)are equally close → return smallerv. - Large values in
arrwith smalltarget(heavy capping).
Test Cases
import unittest
class TestSolution(unittest.TestCase):
def test_examples(self):
s = Solution()
self.assertEqual(s.findBestValue([4, 9, 3], 10), 3)
self.assertEqual(s.findBestValue([2, 3, 5], 10), 5)
self.assertEqual(s.findBestValue([60864, 25176, 27249, 21296, 20204], 56803), 11361)
def test_edge_small_target(self):
s = Solution()
self.assertEqual(s.findBestValue([5, 6, 7], 1), 0)
def test_target_ge_sum(self):
s = Solution()
self.assertEqual(s.findBestValue([1, 2, 3], 100), 3)
def test_single_element(self):
s = Solution()
self.assertEqual(s.findBestValue([10], 3), 3)
self.assertEqual(s.findBestValue([10], 10), 10)
self.assertEqual(s.findBestValue([10], 11), 10)
def test_tie_break(self):
s = Solution()
# v=3 => sum=9 diff=1, v=4 => sum=11 diff=1 => choose 3
self.assertEqual(s.findBestValue([4, 9, 3], 10), 3)
if __name__ == "__main__":
unittest.main()
Common Mistakes
- Not handling tie-breaking correctly (must return the smaller
v). - Binary searching the wrong condition (need the smallest
vwithS(v) >= target). - Forgetting to check
v-1after binary search. - Overflow in languages like Java/C#/Go if using
intfor sums (uselong/int64). - Using linear sum computation inside binary search without prefix sums → can time out (
O(n log maxA)is okay, but still slower; prefix sums make it robust).
Interview Tips
- Start by stating that the mutated sum
S(v)is monotonic, which suggests binary search onv. - Explain how to compute
S(v)efficiently:- sort + prefix sums + upper bound split.
- Mention the key correctness detail:
- binary search gives a “crossing point”; closest answer is among
{v, v-1}with tie → smallerv.
- binary search gives a “crossing point”; closest answer is among
- Be ready to discuss complexity tradeoffs:
- brute force is simple but too slow for large
max(arr). - optimized solution is
O(n log n + log(maxA) log n)and safe for constraints.
- brute force is simple but too slow for large