旋转排序数组是升序数组在某点断开并前后段交换形成的结构,如[4,5,6,7,0,1,2],由两个升序子数组构成;因整体不单调,标准二分失效,需先判断mid所在侧是否升序(如nums[left]≤nums[mid]则左段升序),再据target是否落在该升序段内收缩区间。

旋转排序数组是什么结构,为什么不能直接二分
旋转排序数组是把一个升序数组从某个位置断开、前后两段交换得到的,比如 [4,5,6,7,0,1,2]。它整体不是单调的,但由两个升序段拼成——这导致标准二分查找的 mid 判断失效:你没法单靠 nums[mid] 和 target 的大小关系确定目标在左还是右。
关键点在于:**左半段(从 left 开始)或右半段(到 right 结束)至少有一段是严格升序的**。我们得先判断哪一段有序,再看 target 是否落在该段范围内。
如何判断哪边是升序段并收缩区间
每次取 mid = left + (right - left) / 2 后,比较 nums[left] 和 nums[mid]:
- 若
nums[left] ,说明左半段 <code>[left, mid]是升序的 - 否则右半段
[mid, right]是升序的
接着检查 target 是否落在这个升序段内:
- 左段升序且
nums[left] → 搜索左段,<code>right = mid - 1 - 左段升序但
target不在此范围 → 搜索右段,left = mid + 1 - 右段升序且
nums[mid] → 搜索右段,<code>left = mid + 1 - 右段升序但
target不在此范围 → 搜索左段,right = mid - 1
注意边界等号:因为 nums[left] 和 nums[right] 都可能是 target,必须包含。
重复元素会让算法失效吗
会。当 nums[left] == nums[mid] == nums[right] 时(比如 [1,1,1,2,1]),无法判断哪边升序,此时只能收缩边界跳过重复值:
- 若
nums[left] == nums[mid],执行++left - 若
nums[right] == nums[mid],执行--right
这种退化情况最坏时间复杂度变成 O(n),但无重复时仍是 O(log n)。实际编码中如果明确无重复,可省略这步判断。
边界条件和易错点
最容易出错的是循环条件和下标更新方式:
- 用
while (left ,不是 <code> —— 因为单个元素也要检查 -
mid计算必须用left + (right - left) / 2,防止整数溢出 - 更新
left或right时,一定要跳过mid(即mid + 1或mid - 1),否则可能死循环 - 当
nums[mid] == target时立即返回,不要等到循环结束再判断
漏掉任一条件都可能导致无限循环或漏解,尤其在数组长度为 1 或 2 时要手动验证几个 case。
旋转数组搜索的核心不是“改二分”,而是“每次主动识别一个可信的升序区间,再做经典二分决策”。真正难的不是写对,是在 ==、、<code>++left 这些细节上不手滑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











