因为旋转数组非全局有序,std::lower_bound要求严格升序,否则行为未定义;必须手写二分逻辑:每次取mid后,若nums[left] <= nums[mid]则左半段有序,否则右半段有序,再据此判断target是否在有序段内并收缩区间。

旋转数组里二分查找为什么不能直接套 std::lower_bound
因为旋转排序数组不是全局有序的,std::lower_bound 要求容器严格升序,否则行为未定义——哪怕数组只转了一次(比如 [4,5,6,7,0,1,2]),直接传给它会返回错误位置甚至越界。
必须手写逻辑,在每次 mid 判断后,根据「哪一段是有序的」来收缩区间。
关键点在于:任意一次划分后,left ~ mid 和 mid ~ right 必有一段严格有序。利用这点才能安全比较、丢弃一半。
如何判断哪边有序并决定搜索方向
以 nums[left] 为条件判断左半段是否有序(注意等号,处理单元素或重复边界):
立即学习“C++免费学习笔记(深入)”;
- 若成立:左半段有序 → 若
target落在[nums[left], nums[mid]]内,则right = mid - 1;否则left = mid + 1 - 否则:右半段有序 → 若
target落在[nums[mid], nums[right]]内,则left = mid + 1;否则right = mid - 1
注意:nums[mid] 每次都要和 target 对比,相等就直接返回 mid;边界更新永远用 mid ± 1,避免死循环。
示例片段(无重复元素):
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
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;
}遇到重复元素时 nums[left] == nums[mid] 怎么办
当 nums[left] == nums[mid],无法确定哪边有序(比如 [2,2,2,0,2,2] 中,left=0, mid=2,值都是 2,但最小值在右边)。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
此时唯一安全做法是收缩左边界:left++,跳过这个不确定的值。虽然最坏退化到 O(n),但能保证正确性。
修改判断条件为:
- 若
nums[left] < nums[mid]→ 左有序 - 若
nums[left] > nums[mid]→ 右有序 - 若
nums[left] == nums[mid]→left++,继续下一轮
别试图“跳过多个”,每次只 ++ 一次,否则可能漏掉 target。
边界和空数组这些细节容易漏掉
函数开头必须检查 nums.empty(),否则 right = -1 会导致 while 条件异常或后续访问越界。
left 和 right 初始化要对齐索引范围:right = nums.size() - 1,不是 nums.size();循环条件用 left <= right,不是 < —— 否则单元素数组会直接退出。
返回值统一用 -1 表示未找到,别用 nums.size() 或其他 magic number,和 STL 习惯一致也方便调用方处理。
真正麻烦的从来不是二分本身,而是旋转带来的局部有序性判断——一旦 left、mid、right 三个点值关系没理清,分支就容易写反。建议在纸上画两组数(含重复),手动走一遍流程再敲代码。

















