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

有序数组,距离目标最近的k个数 二分查找

  🤔 新手做题思路:

  第1步:理解题目

  - 找距离x最近的k个数
- 数组已排序
- 返回结果也要排序(升序)
- 距离相同时,选择较小的数

  第2步:关键insight

  - 数组已排序 → 考虑二分查找
- 最近的k个数一定是连续的k个数 → 考虑滑动窗口/双指针
- 只需要找到这个连续区间的起始位置

数组排序和二分查找有关 ,注意滑动窗口不用排序

指定的子串长度和滑动窗口有关

  第3步:核心思想

  最近的k个数字一定形成一个长度为k的连续子数组,问题转化为:
在所有长度为k的子数组中,找到距离x总和最小的那个

● 💡 解题方法(从简单到优化):

  方法1:暴力法(新手先理解这个)

  def findClosestElements_brute(arr, k, x):# 计算每个元素与x的距离,然后排序distances = []for num in arr:distances.append((abs(num - x), num))# 按距离排序,距离相同时按值排序distances.sort(key=lambda item: (item[0], item[1]))# 取前k个元素result = [item[1] for item in distances[:k]]# 返回排序结果return sorted(result)

  方法2:双指针法(推荐理解)

  def findClosestElements_two_pointers(arr, k, x):left, right = 0, len(arr) - 1# 收缩到k个元素while right - left >= k:# 比较左右边界哪个离x更远,移除更远的if abs(arr[left] - x) > abs(arr[right] - x):left += 1elif abs(arr[left] - x) < abs(arr[right] - x):right -= 1else:# 距离相同,移除更大的数if arr[left] > arr[right]:left += 1else:right -= 1return arr[left:right + 1]

  方法3:二分查找(最优解)

  def findClosestElements_binary(arr, k, x):# 二分查找最佳起始位置left, right = 0, len(arr) - kwhile left < right:mid = (left + right) // 2# 比较mid位置和mid+k位置哪个更适合作为起点# 如果x离右边界更近,说明最佳区间应该右移if x - arr[mid] > arr[mid + k] - x:left = mid + 1else:right = midreturn arr[left:left + k]

  🔍 详细解析双指针法(最容易理解):

  核心思想:

  - 初始时:左指针=0,右指针=n-1(包含所有元素)
- 目标:缩小到恰好k个元素
- 策略:每次移除距离x最远的边界元素

  手动模拟:

  arr = [1,2,3,4,5], k = 4, x = 3

  初始: left=0, right=4, 区间=[1,2,3,4,5] (5个元素)
比较: |1-3|=2 vs |5-3|=2,距离相等,移除较大的5
结果: left=0, right=3, 区间=[1,2,3,4] (4个元素) ✓

  完整代码实现:

● def findClosestElements(arr, k, x):
"""
推荐的双指针解法
时间复杂度: O(n)
空间复杂度: O(1)
"""
left, right = 0, len(arr) - 1

      # 收缩窗口直到剩下k个元素
while right - left + 1 > k:
# 计算左右边界与x的距离
left_dist = abs(arr[left] - x)
right_dist = abs(arr[right] - x)

          if left_dist > right_dist:
# 左边更远,移除左边
left += 1
elif left_dist < right_dist:
# 右边更远,移除右边
right -= 1
else:
# 距离相等,移除数值更大的(题目要求)
if arr[left] > arr[right]:
left += 1
else:
right -= 1

      return arr[left:right + 1]

  # 测试
print(findClosestElements([1,2,3,4,5], 4, 3))      # [1,2,3,4]
print(findClosestElements([1,1,2,3,4,5], 4, -1))  # [1,1,2,3]

  🚀 二分查找优化版(面试加分):

  def findClosestElements_optimal(arr, k, x):
"""
二分查找最优起始位置
时间复杂度: O(log n)
空间复杂度: O(1)
"""
# 在[0, n-k]范围内找最佳起始位置
left, right = 0, len(arr) - k

      while left < right:
mid = (left + right) // 2

          # 关键判断:比较mid和mid+k位置
# 如果x更靠近右边界,说明最优区间应该右移
if x - arr[mid] > arr[mid + k] - x:
left = mid + 1
else:
right = mid

      return arr[left:left + k]

  🎯 复杂度对比:

  | 方法   | 时间复杂度      | 空间复杂度 | 难度  |
|------|------------|-------|-----|
| 暴力法  | O(n log n) | O(n)  | ⭐   |
| 双指针  | O(n)       | O(1)  | ⭐⭐  |
| 二分查找 | O(log n)   | O(1)  | ⭐⭐⭐ |

  📝 考试建议:

  优先掌握双指针法:
- 思路清晰,容易理解
- 代码简洁,不容易出错
- 时间复杂度已经很好了

  二分查找法作为加分项:
- 面试时展现算法功底
- 但逻辑相对复杂,容易出错

  ★ Insight ─────────────────────────────────────
这道题的关键洞察是:最近的k个元素必然是连续的。因为如果不连续,中间跳过的元素肯定比端点的某个元素更接近x,这与最优性矛盾。基于这个洞察,问题就转化为寻找最
优的连续k元素子数组,可以用双指针或二分查找来高效求解。
─────────────────────────────────────────────────


文章转载自:

http://VTZyGkoz.LLfwg.cn
http://yb5ZWp4z.LLfwg.cn
http://IVnEmBE3.LLfwg.cn
http://JCFbK2Dq.LLfwg.cn
http://uVsw9WBw.LLfwg.cn
http://CJ7f4zjP.LLfwg.cn
http://7HYfMulw.LLfwg.cn
http://mmfrkvU4.LLfwg.cn
http://91KLXc5R.LLfwg.cn
http://jDYoBVZL.LLfwg.cn
http://xQIJvLOK.LLfwg.cn
http://NIdnk1xo.LLfwg.cn
http://EcweSFkX.LLfwg.cn
http://TYhHEcb6.LLfwg.cn
http://LJVy6qCI.LLfwg.cn
http://EUkVo45m.LLfwg.cn
http://xcmCnFHn.LLfwg.cn
http://CPscuF0R.LLfwg.cn
http://fWibWay9.LLfwg.cn
http://xiuIFIsr.LLfwg.cn
http://o0dQgkGm.LLfwg.cn
http://t1SGemnW.LLfwg.cn
http://83ldctZM.LLfwg.cn
http://XfLar2lB.LLfwg.cn
http://AByMAdz9.LLfwg.cn
http://P0oHrReG.LLfwg.cn
http://IJW2GY93.LLfwg.cn
http://o4b3b10t.LLfwg.cn
http://nTNw4jl0.LLfwg.cn
http://dWqMRi4Q.LLfwg.cn
http://www.dtcms.com/a/368562.html

相关文章:

  • 函数式组件父子ref通讯
  • AAB包转apks转apk
  • 快速、归并、堆、希尔、ArrayList排序
  • 【73页PPT】美的简单高效的管理逻辑(附下载方式)
  • OctShop点单系统+收银系统+商城系统+IM在线客服系统一体化源码
  • 大彩串口屏-烧录与调试
  • Linux之Docker虚拟化技术(四)
  • JS中的String的常用方法
  • Linux调试命令速查:Java/微服务必备
  • 一文吃透 Protobuf Proto3 语法 + 风格规范 + 枚举行为全解(含检查清单与示例)
  • 第24节:3D音频与空间音效实现
  • AI Compass前沿速览:Kimi K2、InfinityHuman-AI数字人、3D-AI桌面伴侣、叠叠社–AI虚拟陪伴
  • 8051单片机-蜂鸣器
  • 来WAVE SUMMIT,文心快码升级亮点抢先看!
  • Redis 深度解析:数据结构、持久化与集群
  • MyBatis高频问题-自动映射与缓存解析
  • 力扣152:乘积最大子数组
  • honmony 中集成 tuanjie/unity
  • (二)文件管理-基础命令-rm命令的使用
  • 鸿蒙系统开发资料汇总:全面助力鸿蒙开发HarmonyOS
  • 手写React状态hook
  • scrypt 密钥派生算法(RFC7914)技术解析及源码示例
  • 案例分享|企微智能会话风控系统:为尚丰盈铝业筑牢沟通安全防线
  • Docker部署Drawnix开源白板工具
  • linux缺页中断频繁怎么定位
  • 代码随想录70期day3
  • AI驱动开发:颠覆传统编程新范式
  • 第三方web测评机构:【WEB安全测试中HTTP方法(GET/POST/PUT)的安全风险检测】
  • PAT 1096 Consecutive Factors
  • 53.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--新增功能--集成短信发送功能