LeetCode 1300题解析:二分查找优化数组和最接近目标值

📅 2026/7/31 9:22:49
LeetCode 1300题解析:二分查找优化数组和最接近目标值
1. 问题背景与题目解析今天我们来拆解LeetCode第1300题——Sum of Mutated Array Closest to Target。这是一道中等难度的算法题主要考察对数组操作和二分查找的应用能力。题目要求我们将给定数组转变为一个特定形式的数组使得转变后的数组和最接近目标值。题目具体描述如下 给定一个整数数组arr和一个目标值target我们需要找到一个整数value使得将数组中所有大于value的元素替换为value后数组的和最接近target。如果有多个value满足条件我们选择最小的那个。举个例子 输入arr [4,9,3], target 10 输出3 解释当选择value3时数组变为[3,3,3]和为9与target的差值为1选择value4时数组变为[3,4,4]和为11差值也是1。我们选择较小的value3。2. 解题思路分析2.1 暴力解法与优化方向最直观的解法是暴力枚举所有可能的value值计算对应的数组和然后找出最接近target的那个value。但是这种方法的时间复杂度是O(n*max(arr))当数组元素很大时效率极低。我们需要寻找更高效的解法。观察题目特点当value增加时数组和单调不减我们需要找到使数组和最接近target的value 这些特征提示我们可以使用二分查找来优化搜索过程。2.2 二分查找的应用二分查找通常用于在有序序列中快速定位目标值。在本问题中我们可以将value的可能取值看作一个有序序列从0到max(arr)然后通过二分法快速定位最优value。具体思路确定搜索范围value的最小可能值是0最大值是原数组的最大值因为更大的value不会改变数组和在搜索范围内进行二分查找对于每个中间值mid计算对应的数组和根据数组和与target的比较结果调整搜索范围记录最接近target的value3. 详细实现步骤3.1 预处理与边界情况首先处理一些边界情况如果数组和已经小于等于target直接返回数组最大值因为此时增大value只会使和更大偏离target如果数组最小值乘以数组长度大于target返回target/数组长度因为此时所有元素都需要缩小def findBestValue(arr, target): arr.sort() n len(arr) prefix [0] for num in arr: prefix.append(prefix[-1] num) # 边界情况处理 if prefix[-1] target: return arr[-1] if arr[0] * n target: value target // n if abs(value * n - target) abs((value 1) * n - target): return value else: return value 13.2 二分查找实现接下来实现二分查找的核心部分left, right 0, arr[-1] best_value 0 min_diff float(inf) while left right: mid (left right) // 2 # 找到第一个大于mid的元素索引 index bisect.bisect_right(arr, mid) current_sum prefix[index] (n - index) * mid current_diff abs(current_sum - target) # 更新最优解 if current_diff min_diff or (current_diff min_diff and mid best_value): min_diff current_diff best_value mid # 调整搜索范围 if current_sum target: left mid 1 else: right mid - 1 return best_value3.3 计算数组和的优化为了快速计算转变后的数组和我们使用了前缀和技巧先对数组排序计算前缀和数组对于给定的value使用二分查找确定哪些元素需要被替换数组和 不需要替换的元素和 需要替换的元素个数 * value这种方法将每次计算数组和的时间复杂度从O(n)降低到O(logn)大大提高了整体效率。4. 复杂度分析与优化验证4.1 时间复杂度分析让我们分析算法的时间复杂度排序数组O(nlogn)计算前缀和O(n)二分查找O(log(max(arr)))每次二分查找中的操作O(logn)bisect操作 因此总时间复杂度为O(nlogn log(max(arr)) * logn)4.2 空间复杂度分析空间复杂度主要来自存储排序后的数组O(n)前缀和数组O(n) 因此总空间复杂度为O(n)4.3 正确性验证让我们验证几个测试用例示例1 输入[4,9,3], target10 输出3 验证value3时和为9差值为1value4时和为11差值也是1。选择较小的3正确。示例2 输入[2,3,5], target10 输出5 验证value5时和为10正好等于target正确。边界情况 输入[1,2,3], target100 输出3 验证数组和已经小于target返回最大值3正确。5. 实际编码中的注意事项5.1 整数除法的处理在计算target//n时需要注意Python的整数除法是向下取整。我们需要比较value和value1两种情况value target // n if abs(value * n - target) abs((value 1) * n - target): return value else: return value 15.2 等距离情况的处理当两个不同的value对应的数组和与target的差值相等时我们需要选择较小的value。这在二分查找的更新步骤中需要特别注意if current_diff min_diff or (current_diff min_diff and mid best_value): min_diff current_diff best_value mid5.3 二分查找终止条件二分查找的终止条件是left right但在此之前我们已经记录了最佳解。不需要等到循环结束才返回结果。6. 算法优化与变种思考6.1 双指针优化在已经排序的数组中我们可以使用双指针技术替代二分查找来定位需要替换的元素这将进一步优化时间复杂度index 0 while index n and arr[index] mid: index 16.2 浮点数解的可能性如果允许value为浮点数我们可以得到更精确的解。但题目要求value必须是整数因此我们需要在相邻整数中选择更优解。6.3 多目标优化考虑扩展问题如果有多个target需要处理我们可以预先计算所有可能的value和对应的数组和然后对每个target进行查询。这种情况下预处理的时间可能更值得。7. 完整代码实现以下是完整的Python解决方案import bisect def findBestValue(arr, target): arr.sort() n len(arr) prefix [0] for num in arr: prefix.append(prefix[-1] num) # 边界情况处理 if prefix[-1] target: return arr[-1] if arr[0] * n target: value target // n if abs(value * n - target) abs((value 1) * n - target): return value else: return value 1 left, right 0, arr[-1] best_value 0 min_diff float(inf) while left right: mid (left right) // 2 index bisect.bisect_right(arr, mid) current_sum prefix[index] (n - index) * mid current_diff abs(current_sum - target) # 更新最优解 if current_diff min_diff or (current_diff min_diff and mid best_value): min_diff current_diff best_value mid # 调整搜索范围 if current_sum target: left mid 1 else: right mid - 1 return best_value8. 测试用例设计为了确保代码的正确性我们应该设计全面的测试用例常规情况assert findBestValue([4,9,3], 10) 3 assert findBestValue([2,3,5], 10) 5边界情况assert findBestValue([1,2,3], 100) 3 # 数组和小于target assert findBestValue([100,200,300], 50) 17 # 所有元素都需要缩小等距离情况assert findBestValue([1,2,3,4,5], 11) 3 # sum10和sum12都差1选较小的3极值情况assert findBestValue([], 10) 0 # 空数组 assert findBestValue([5], 10) 5 # 单元素数组9. 实际应用场景这类问题在实际开发中有多种应用场景资源分配在有限的资源(target)下如何公平地限制每个用户的资源使用(value)图像处理像素值归一化时如何选择截断阈值数据压缩在保持数据总和接近原数据的前提下如何减少数据值的范围理解这类问题的解法有助于我们在面对实际工程问题时能够快速识别问题模式并应用合适的算法解决。