因为nums[mid] == nums[left]时无法确定哪边有序,如[2,2,2,0,1,2]中left=0、mid=2均为2,但左右均非完全有序,盲目缩边可能漏掉target;故只能安全地left++一步,保留所有可能性。

为什么 nums[mid] == nums[left] 时不能直接缩边界
旋转数组里存在重复元素时,nums[left] == nums[mid] 无法判断哪边有序。比如 [2,2,2,0,1,2],left=0、mid=2,三者都是 2,但左半段无序、右半段也非完全有序——此时若盲目丢掉 left 或 mid,可能把目标值过滤掉。
正确做法是只收缩左边界一步:left++,保留所有可能性。这不是优化策略,而是必要退让。
- 仅当
nums[left] == nums[mid]且nums[mid] != target时才执行left++ - 必须配合循环条件为
left ,否则会漏判单元素区间 - 这个分支不更新
mid,下轮重新计算,避免逻辑跳跃
if (nums[left] 判断的是「左段是否有序」,不是「是否递增」
旋转点把原升序数组切成两段,其中一段必然保持内部有序(即满足 nums[i] 对该段内任意 <code>i<j> 成立)。用 <code> 而非 <code> 是为了兼容单元素或重复元素场景,例如 <code>[1,1,1,2] 中 nums[0] 成立,左段确实有序。
- 若成立,说明
[left, mid]有序 → 检查target是否落在该区间:用nums[left] - 若不成立,说明
[mid, right]有序 → 检查nums[mid] - 注意两次比较都用闭区间,因为端点值可能等于
target
查找失败时返回 -1,但要注意 right 更新不能越界到 mid-1 以下
标准二分中 right = mid - 1 安全,但在旋转数组中,如果仅靠 nums[mid] 和 target 大小关系缩边界(比如写成 if (nums[mid] > target) right = mid - 1),会破坏有序性假设,导致漏解。必须严格依据「哪边有序 + target 是否在该有序段内」来更新。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 错误写法:
if (nums[mid] > target) right = mid - 1—— 在[4,5,6,7,0,1,2]查0时,第一次mid=3、nums[3]=7 > 0,却把right错缩到 2,丢掉含 0 的右半段 - 正确路径:先判左段有序(
4 成立),再看 <code>target=0是否在[4,7]内 → 否 →left = mid + 1 - 所有
left/right更新必须来自明确的有序段归属判断
测试用例要覆盖重复+边界交叉,比如 [1,1,1,1,1,1,1,1,2,1,1]
这种数组旋转点在末尾附近,且大量重复,极易暴露判断逻辑漏洞。特别是当 target == nums[left] == nums[mid] 但不在左段时(如查 2),必须靠多次 left++ 跳过重复,直到出现 nums[left] != nums[mid] 才能恢复有序段判断能力。
- 最差情况时间复杂度退化为
O(n),这是重复元素下的理论下限,无法避免 - 不要试图用「跳到第一个不同值」优化,容易越界或死循环;
left++单步最稳 - 实际编码中建议加个防死循环保护:比如迭代次数超
nums.size()就返回 -1(虽极少触发,但调试时很管用)
重复元素带来的不确定性,本质是信息缺失——你永远不知道当前相等的值是来自旋转前的同一段,还是横跨了旋转点。这时候少做假设,多走一步,反而更可靠。

















