news 2026/6/12 9:46:01

旋转数组里找数,AI 用二分写了 3 版才写对,差距在哪

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
旋转数组里找数,AI 用二分写了 3 版才写对,差距在哪

读完本文你将了解:旋转排序数组的二分查找核心思路 | AI 从暴力到最优的 3 版演进 | 面试中的关键边界处理


📋 题目

原题:给定一个经过旋转的升序数组 nums(如 [4,5,6,7,0,1,2])和一个目标值 target,在 O(log n) 时间内找到 target 的下标,不存在则返回 -1。

项目说明
输入nums = [4,5,6,7,0,1,2], target = 0
输出4
约束1 ≤ nums.length ≤ 5000,nums 中无重复元素,元素值唯一

💡 先问一个问题

如果你让 ChatGPT 写这道题,第一版代码会是怎样?

给你一个提示:它八成会先遍历一遍数组找到旋转点,然后再做二分查找。

这不算错——时间 O(n),空间 O(1),能 AC。但面试官要的是 O(log n),你给 O(n),这就有点尴尬了。

来看看 AI 怎么一步步自己纠正的。

🤖 第一版:AI 的朴素思路(找旋转点 + 二分)

defsearch(nums,target):# 找旋转点pivot=0foriinrange(1,len(nums)):ifnums[i]<nums[i-1]:pivot=ibreak# 在两个有序段中分别二分defbinary_search(left,right):whileleft<=right:mid=(left+right)//2ifnums[mid]==target:returnmidelifnums[mid]<target:left=mid+1else:right=mid-1return-1result=binary_search(0,pivot-1)ifresult!=-1:returnresultreturnbinary_search(pivot,len(nums)-1)

AI 的思路很"人类"——先把旋转点找到,数组切成两段有序区间,再各自二分。直觉上没毛病。

问题在哪?找旋转点用了 O(n) 的单次遍历。题目要求 O(log n),这一步就超了。

复杂度:时间 O(n) + O(log n) → O(n),空间 O(1)

🧠 AI 的自我优化

把这段代码丢回给 AI,让它优化:

第 1 次优化:二分找旋转点

AI 意识到找旋转点也可以用二分——因为旋转后的数组,旋转点左边的元素都大于等于 nums[0],旋转点右边的元素都小于 nums[0]。

deffind_pivot(nums):left,right=0,len(nums)-1whileleft<right:mid=(left+right)//2ifnums[mid]>nums[right]:left=mid+1else:right=midreturnleft

这一步把找旋转点降到了 O(log n)。整体变成O(log n) + O(log n) = O(log n),已经达标了。

第 2 次优化:一步到位,不找旋转点直接二分

但 AI 接着发现:其实根本不需要先找旋转点——可以在一次二分搜索中同时处理旋转的情况。

关键发现:任意一个 mid 切下去,mid 的左右两边,必有一边是完全有序的。只需要判断 target 落在有序的那一半就行。

defsearch(nums,target):left,right=0,len(nums)-1whileleft<=right:mid=(left+right)//2ifnums[mid]==target:returnmid# 判断哪一半是有序的ifnums[left]<=nums[mid]:# 左半有序ifnums[left]<=target<nums[mid]:right=mid-1else:left=mid+1else:# 右半有序ifnums[mid]<target<=nums[right]:left=mid+1else:right=mid-1return-1

时间 O(log n),空间 O(1)。完美满足题目要求。而且代码比两段式更短、更优雅。

☕ Java 实现(思路完全一致)

publicintsearch(int[]nums,inttarget){intleft=0,right=nums.length-1;while(left<=right){intmid=left+(right-left)/2;if(nums[mid]==target){returnmid;}if(nums[left]<=nums[mid]){// 左半有序if(nums[left]<=target&&target<nums[mid]){right=mid-1;}else{left=mid+1;}}else{// 右半有序if(nums[mid]<target&&target<=nums[right]){left=mid+1;}else{right=mid-1;}}}return-1;}

为什么要加 Java?CSDN 第一大用户群是 Java 开发者。用mid = left + (right - left) / 2防溢出,Java 面试官一定会揪。两版代码放一起,读者自己比,比我讲十句都有用。

下面是演进路线的可视化:

暴力遍历找旋转点
O(n)

二分找旋转点
O(log n) + O(log n)

一步到位
O(log n),单次遍历

🔍 算法模式拆解:Modified Binary Search

这道题属于Modified Binary Search(变体二分搜索)模式。

经典二分的前提是「数组完全有序」。这道题的数组虽然被旋转了,但部分有序性还在——旋转点两侧各自保持升序,只是整体被截断了。

模式核心:每一次二分,至少能确定一半区间是有序的。利用「有序的一半」来判断 target 在哪。

识别这个模式的关键特征:

特征说明
数据有某种"部分有序"结构旋转数组、山脉数组、近有序数组
要求 O(log n) 时间排除线性扫描的可能性
不能直接套标准二分需要额外的条件判断

同类变体:

  • LeetCode 81:允许重复元素(最坏退化为 O(n))
  • LeetCode 153:找旋转数组的最小值
  • 山脉数组峰顶查找:先升后降的单峰结构

🏗️ 真实产品场景

这个模式在工程中出镜率挺高。

场景:版本回归检测

想象你维护一个 CI/CD Pipeline。每天晚上跑一次回归测试。某天突然发现测试挂了——但你不确定是最近哪次提交导致的。

你手上有最近 N 次构建的状态数组:[通过, 通过, 通过, 失败, 失败, 失败](之前都通过,某次开始全失败)。

这就是一个旋转数组的变体——用 Modified Binary Search 可以在O(log N)次测试中找到第一个失败的构建,而不是逐个回溯。

每日构建状态列表

mid 通过?

bug 在右半边

bug 在左半边或就是 mid

二分继续缩小范围

O(log N) 定位到首次失败的提交

另一个场景:循环日志缓冲区搜索。高性能系统的日志常常循环写入——最新日志在缓冲区中间某个位置,最旧的在它后面。要快速查到某个时间戳的日志,就把时间戳当 target,二分定位。

还有一个你可能每天在用但没意识到的例子:数据库 B+Tree 的范围查询优化。当查询范围跨越多页时,MySQL 的优化器会在旋转后的页链表中用类似二分的方式快速定位起始位置——本质就是这道题的思路。

✅ 面试官的点评

这道题是 Medium 里的"Hard 敲门砖"——面试官考这题,不是看你会不会写二分,而是看你能不能识别"部分有序"这个关键结构

写到什么程度算"通过":

  • 能说清楚「每次二分,至少有一半有序」这个核心点
  • 边界条件处理正确(nums[left] <= nums[mid]里的等号很关键)
  • 时间 O(log n)

加分项:

  • mid = left + (right - left) / 2而不是(left + right) / 2(防溢出)
  • 能讨论 repeat 元素的退化情况(81 题)
  • 能关联到真实工程场景

常见踩坑点:

  • 忘了判断 mid 等于 target 时直接返回
  • nums[left] <= nums[mid]写成<导致 [3,1] 这种两元素情况出错
  • target 范围判断时漏掉等于号

📊 同类题推荐

题目一句话思路
LeetCode 81:Search in Rotated Sorted Array II含重复元素,无法区分哪边有序时左右各缩一步
LeetCode 153:Find Minimum in Rotated Sorted Array只找最小值,比找 target 更简单,比较 mid 和 right
LeetCode 162:Find Peak Element二分搜索局部峰值,不需要全局有序

来源说明

  • ✅ 已验证:LeetCode 33 官方题解 + AI 代码实测(Python 3 + Java 17 均可运行)
  • 📄 文档:算法导论第 2 章「二分查找及其变体」
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/12 9:43:56

X-AnyLabeling一键可用的YOLOX-s轻量ONNX自动标注方案

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;直接放进X-AnyLabeling就能用的YOLOX-s自动标注组合&#xff1a;包含已导出的yolox_s.onnx模型文件和配套yolox_s.yaml配置文件&#xff0c;无需转换、不需编译&#xff0c;复制到软件models目录后&#xff0c;…

作者头像 李华
网站建设 2026/6/12 9:39:52

推荐系统范式迁移:从预测喜欢到支持决策

1. 项目概述&#xff1a;这不是在调参&#xff0c;是在重建推荐系统的底层认知“Reimagining the Recommendation Engine”——这个标题里没有一个技术名词&#xff0c;却比任何“TransformerGraphSAGEMulti-Task Learning”的堆砌更让人脊背一紧。我在电商中台干了七年推荐系统…

作者头像 李华
网站建设 2026/6/12 9:38:16

三万随便用 +AI Copilot,报表工具从商业到技术的双重颠覆

引子&#xff1a;两个场景&#xff0c;一场关于成本的噩梦与渴望 场景一&#xff1a;好消息变坏消息的报表成本失控案例 好消息是&#xff1a;今年新签了 8 个项目&#xff0c;要部署 20 个节点 坏消息是&#xff1a;每个节点都需要买报表工具&#xff0c;一套大几万&#xff…

作者头像 李华
网站建设 2026/6/12 9:36:54

3步掌握碧蓝航线自动化脚本:让游戏回归乐趣

3步掌握碧蓝航线自动化脚本&#xff1a;让游戏回归乐趣 【免费下载链接】AzurLaneAutoScript Azur Lane bot (CN/EN/JP/TW) 碧蓝航线脚本 | 无缝委托科研&#xff0c;全自动大世界 项目地址: https://gitcode.com/gh_mirrors/az/AzurLaneAutoScript 还在为碧蓝航线中重复…

作者头像 李华
网站建设 2026/6/12 9:36:51

3步配置实现PotPlayer字幕实时翻译:百度翻译插件完全指南

3步配置实现PotPlayer字幕实时翻译&#xff1a;百度翻译插件完全指南 【免费下载链接】PotPlayer_Subtitle_Translate_Baidu PotPlayer 字幕在线翻译插件 - 百度平台 项目地址: https://gitcode.com/gh_mirrors/po/PotPlayer_Subtitle_Translate_Baidu 还在为观看外语视…

作者头像 李华
网站建设 2026/6/12 9:36:03

揭秘华硕笔记本性能调优神器:G-Helper深度实战指南

揭秘华硕笔记本性能调优神器&#xff1a;G-Helper深度实战指南 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook, Exper…

作者头像 李华