当前位置: 首页 > news >正文

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

1. 问题背景与理解

leetcode 1300题"Sum of Mutated Array Closest to Target"是一个典型的算法优化问题。题目要求我们找到一个整数值value,使得将数组中所有大于value的元素替换为value后,数组的和最接近给定的目标值target。如果有多个value满足条件,则返回最小的那个。

这个问题在实际开发中有很多应用场景,比如资源分配、预算控制等。例如,我们需要将一组服务器的负载调整到一个目标值,但又不想过度调整,这时候就需要找到最接近目标值的调整方案。

2. 问题分析与解法思路

2.1 暴力解法分析

最直观的解法是暴力枚举所有可能的value值。由于数组中的元素都是正整数,value的可能取值范围是从0到数组中的最大值。对于每个value,我们计算转变后的数组和,然后找到最接近target的那个。

def findBestValue(arr, target): arr.sort() n = len(arr) min_diff = float('inf') best_value = 0 for value in range(0, arr[-1] + 1): total = 0 for num in arr: total += min(num, value) diff = abs(total - target) if diff < min_diff: min_diff = diff best_value = value elif diff == min_diff and value < best_value: best_value = value return best_value

这个解法的时间复杂度是O(n*max(arr)),当数组元素较大时效率很低。

2.2 优化思路:二分查找

观察到转变后的数组和sum(value)是关于value的单调非递减函数,我们可以使用二分查找来优化。具体思路是:

  1. 先对数组排序
  2. 确定value的可能范围[0, max(arr)]
  3. 在范围内进行二分查找,计算每个中间值对应的数组和
  4. 根据数组和与target的关系调整查找范围
def findBestValue(arr, target): arr.sort() n = len(arr) prefix = [0] for num in arr: prefix.append(prefix[-1] + num) left, right = 0, arr[-1] best_value = 0 min_diff = float('inf') while left <= right: mid = (left + right) // 2 # 找到第一个大于mid的元素索引 index = bisect.bisect_left(arr, mid) total = prefix[index] + (n - index) * mid diff = abs(total - target) if diff < min_diff or (diff == min_diff and mid < best_value): min_diff = diff best_value = mid if total < target: left = mid + 1 else: right = mid - 1 return best_value

这个解法的时间复杂度是O(nlogn),主要来自排序和二分查找。

3. 关键实现细节

3.1 前缀和优化

为了快速计算转变后的数组和,我们可以预先计算前缀和。这样对于任意value,我们可以:

  1. 使用二分查找找到第一个大于value的元素位置index
  2. 前index个元素的和就是prefix[index]
  3. 后面n-index个元素都被替换为value,和为(n-index)*value
  4. 总数组和就是prefix[index] + (n-index)*value

3.2 边界条件处理

需要特别注意以下边界条件:

  1. 当value=0时,所有元素都被替换为0
  2. 当value≥max(arr)时,数组和就是原数组和
  3. 当target≤0时,最佳value显然是0
  4. 当target≥sum(arr)时,最佳value是max(arr)

3.3 查找终止条件

二分查找的终止条件是left>right。在查找过程中,我们需要记录当前的最小差值min_diff和对应的best_value。当遇到相同差值时,选择较小的value。

4. 复杂度分析

  • 时间复杂度:O(nlogn)
    • 排序:O(nlogn)
    • 前缀和计算:O(n)
    • 二分查找:O(logn),每次查找需要O(logn)时间计算数组和
  • 空间复杂度:O(n),用于存储前缀和

5. 实际应用与变种

5.1 资源分配问题

这个问题可以应用于资源分配场景。例如,有n个项目需要资金,每个项目原始申请资金为arr[i],但总预算只有target。我们需要确定一个上限value,使得:

  1. 任何项目的资金不超过value
  2. 总资金最接近target
  3. 如果有多个value满足条件,选择最小的那个

5.2 变种问题

  1. 如果允许部分元素不被替换(即可以选择性地替换某些元素),问题会变得更复杂,可能需要动态规划解决
  2. 如果数组元素可以是负数,需要调整算法逻辑
  3. 如果要求数组和必须不小于target,可以修改二分查找的条件

6. 常见错误与调试技巧

6.1 常见错误

  1. 忘记处理多个value产生相同差值的情况
  2. 二分查找范围设置不正确(应该从0到max(arr))
  3. 前缀和计算错误(注意前缀和数组的长度是n+1)
  4. 没有考虑target小于0或大于sum(arr)的边界情况

6.2 调试技巧

  1. 对于小规模输入,先手动计算预期结果
  2. 打印二分查找过程中的中间值和对应的数组和
  3. 检查前缀和计算是否正确
  4. 特别注意边界条件的测试用例

7. 代码优化与最佳实践

7.1 进一步优化

我们可以进一步优化二分查找的实现:

  1. 提前计算sum(arr),用于处理target≥sum(arr)的情况
  2. 在二分查找前先检查边界条件
  3. 使用内置的bisect模块提高查找效率

7.2 Python实现优化版

import bisect def findBestValue(arr, target): arr.sort() n = len(arr) prefix = [0] for num in arr: prefix.append(prefix[-1] + num) total_sum = prefix[-1] if target >= total_sum: return arr[-1] left, right = 0, arr[-1] best_value = 0 min_diff = float('inf') while left <= right: mid = (left + right) // 2 index = bisect.bisect_left(arr, mid) current_sum = prefix[index] + (n - index) * mid diff = abs(current_sum - target) if diff < min_diff or (diff == min_diff and mid < best_value): min_diff = diff best_value = mid if current_sum < target: left = mid + 1 else: right = mid - 1 return best_value

7.3 测试用例设计

好的测试用例应该包括:

  1. 常规情况
  2. target小于最小可能和
  3. target大于最大可能和
  4. 多个value产生相同差值
  5. 数组包含重复元素
  6. 数组只有一个元素

示例测试用例:

assert findBestValue([4,9,3], 10) == 3 assert findBestValue([2,3,5], 10) == 5 assert findBestValue([60864,25176,27249,21296,20204], 56803) == 11361 assert findBestValue([1,2,3], 0) == 0 assert findBestValue([1,2,3], 100) == 3 assert findBestValue([5], 10) == 5

8. 算法选择与比较

8.1 暴力法 vs 二分查找

暴力法虽然简单直观,但在最坏情况下时间复杂度为O(n*max(arr)),当max(arr)很大时效率极低。二分查找通过利用单调性将时间复杂度降低到O(nlogn),是更优的选择。

8.2 其他可能解法

  1. 数学方法:可以尝试推导出一个数学公式直接计算value,但需要考虑多种情况,实现起来比较复杂
  2. 插值查找:在二分查找的基础上改进,根据target的值预测更接近的mid值
  3. 三分查找:适用于某些特殊形式的单峰函数

在实际应用中,二分查找的实现简单且效率足够,是最推荐的方法。

9. 扩展思考

9.1 浮点数版本

如果数组元素和target可以是浮点数,算法需要做以下调整:

  1. 二分查找的终止条件改为right-left<epsilon(某个很小的阈值)
  2. 比较差值时需要考虑浮点精度问题
  3. 返回值可能需要四舍五入到指定精度

9.2 多维扩展

如果数组是二维矩阵,我们需要同时调整行和列的上限值,问题会变得复杂得多,可能需要使用更高级的算法或启发式方法。

9.3 在线算法

如果数组元素是动态变化的,我们需要设计一个在线算法,能够快速响应数组变化并重新计算最佳value。这可能涉及到一些高级数据结构如线段树或树状数组。

http://www.jsqmd.com/news/1283050/

相关文章:

  • 陪诊师考证报名避坑指南:选不对授权机构,你的钱可能白花了 - 品牌排行榜单
  • JAVA毕业设计-基于前后端分离的在线教育资源推送推荐系统 基于 SpringBoot 的个性化学习资源推荐的在线教育平台设计与实现(源码+LW+部署文档+全bao+远程调试+代码讲解等)
  • 158、【Agent】【OpenCode】TuiThreadCmd(RPC 泛型推导)
  • C/C++银行排队叫号系统:多线程并发与数据结构实战
  • AI4S算法实战:从分子设计到逆向工程的完整技术指南
  • 共识算法实现:从工作量证明到权益证明的演进
  • 2026年热电偶厂家:专业K型、S型、铠装热电偶及高温防爆耐磨工业热电偶供应商深度解析 - 优企名品
  • 2026甄选:继电器及扩展模块专业品牌与可靠合作机构 - 优企名品
  • QQ空间历史说说备份完整指南:GetQzonehistory让你的青春记忆永不丢失
  • Envoy 核心配置详解:Listener、Cluster 与 Route 的三角关系
  • 游戏化学习工具提升C语言新手学习效率
  • LangChain智能体开发:从零构建自主决策AI助手
  • 收藏!工业AI落地反直觉:读懂数据比强模型更关键,小白也能看懂!
  • Krea 2技术解析:可控AI图像生成与创作意图理解
  • Simulink混合储能系统仿真与功率分配策略
  • 小白做抖店如何避开侵权风险?一件代发选品和商品发布指南 - 电商分享
  • 四川取水泵船源头厂家选型参考及行业服务优势解读 - 品牌优推
  • Unity Standard Shader BasePass源码深度解析:从PBR原理到性能优化
  • TRAE智能体开发框架:架构解析与实战指南
  • 深圳漏水检测正规公司推荐2026-暗管测漏精准定位-卫生间-厨房-屋顶-阳台-地下室-外墙防水补漏维修指南 - 知途管道科技
  • OpenSees钢筋混凝土柱非线性建模与抗震分析实践
  • GetQzonehistory:5分钟搞定QQ空间数据备份的终极完整指南
  • 从零搭建企业级AI简历筛选Pipeline(附GitHub Star超2.4k的开源评估框架实测报告)
  • Unity游戏动态难度调整实战:基于Firebase Remote Config与A/B测试的数据驱动方案
  • Android+OpenCV实现胶体金卡CT区域自动识别
  • 2026春招AI岗位暴涨超12倍,年薪百万不是梦,小白也能轻松入行!
  • LLM技术在水产养殖智能化中的应用与实践
  • AI智能体开发面试从入门到Offer:面试刷题、STAR话术、项目包装、薪资谈判一文打通
  • OpenClaw自动化代理框架与本地系统对接实战指南
  • 大模型工具调用(Tool Use)技术解析与金融应用实践