旋转排序数组可单次二分查找,核心是每次判断左右哪侧有序:若nums[left]≤nums[mid]则左段有序,否则右段有序;再据target是否在有序段内缩区间,无需先找旋转点。

旋转排序数组不是完全无序,而是由两个升序段拼接而成。二分查找依然适用,关键在于每次迭代时识别哪一侧是有序的,再判断目标是否落在该区间内——不找旋转点,不拆两段,单次二分就能完成。
识别哪一侧子数组有序
取中点 mid,比较 nums[mid] 与 nums[left] 或 nums[right]:
- 若 nums[left] ≤ nums[mid]:说明左半段 [left, mid] 严格升序(因为无重复)
- 若 nums[mid] ≤ nums[right]:说明右半段 [mid, right] 严格升序
- 两者必居其一,不可能都乱序——这是旋转数组的核心性质
根据有序侧决定搜索方向
确认某侧有序后,用目标值 target 和该侧端点比大小,判断是否可能落在其中:
- 若左段有序且 nums[left] ≤ target :目标在左段,收缩 right = mid − 1
- 若左段有序但 target 不在此范围:目标只可能在右段,收缩 left = mid + 1
- 若右段有序且 nums[mid] :目标在右段,收缩 left = mid + 1
- 若右段有序但 target 不在此范围:目标只可能在左段,收缩 right = mid − 1
边界处理与终止条件
使用闭区间 [left, right] 模式更直观:
- 初始化:left = 0, right = nums.length − 1
- 循环条件:while (left ≤ right),避免漏掉单元素区间
- 中点计算:mid = left + (right − left) / 2,防整型溢出
- 命中即返:if (nums[mid] == target) return mid
- 未命中则按上述逻辑收缩区间,最终 left > right 时返回 −1
为什么不用先找最小值或峰值
预找旋转点(如最小值下标)属于“两次二分”,虽可行但多一次 log n 开销,且易在边界出错:
- 找最小值需额外判断 nums[mid] 与 nums[right] 大小,逻辑独立、易写错
- 再根据 target 和 nums[right] 关系选段,又增一层分支
- 而单次二分全程复用同一套区间更新逻辑,代码更短、鲁棒性更高、面试更易讲清

















