不能直接用 std::min_element,因为它盲目遍历整个数组,时间复杂度 O(n),未利用旋转数组由两个升序段构成的局部有序性;应改用二分查找变体,通过比较 nums[mid] 与 nums[right] 判断最小值所在区间,将时间复杂度降至 O(log n)。

为什么不能直接用 std::min_element
旋转排序数组(比如 [4,5,6,7,0,1,2])看似乱,实则由两个升序段拼成。直接遍历找最小值虽可行(O(n)),但浪费了“局部有序”这个关键性质。更糟的是,std::min_element 会扫完整个数组,完全没利用旋转结构——它连哪边该跳过都不知道。
真正该用的是二分查找的变体,时间复杂度压到 O(log n)。核心思路不是找“最小值”,而是找“旋转点”:那个突然变小的位置(比如 7 → 0),它的右边就是最小值。
- 每次比较
nums[mid]和nums[right],而不是和nums[left]—— 后者在[1,3]这类无旋转或单元素时容易误判边界 - 如果
nums[mid] > nums[right],说明最小值一定在右半段(mid还在左升序段里) - 如果
nums[mid] ,最小值在左半段或就是 <code>mid(右段是升序,最小值不可能在右段中间) -
nums[mid] == nums[right]是最麻烦的:可能是重复值(如[2,2,2,0,1,2]),此时只能保守地--right缩小范围
int findMin(vector<int>& nums)</int> 的标准写法
以下是最常用、能处理重复值的版本,使用闭区间 [left, right] 模式,逻辑清晰不易越界:
int findMin(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] > nums[right]) {
left = mid + 1;
} else if (nums[mid] < nums[right]) {
right = mid;
} else {
--right;
}
}
return nums[left];
}
注意三点:
立即学习“C++免费学习笔记(深入)”;
- 循环条件是
left ,不是 <code>,避免死循环;退出时 <code>left == right,指向唯一候选 - 当
nums[mid] 时,<code>right = mid(不是mid - 1),因为mid本身可能是最小值(例如[3,1,2]中mid指向1) - 重复值分支必须用
--right,不能用++left—— 左段可能全等(如[1,1,1,0,1]),砍右边才安全
遇到 Runtime Error: index out of bounds 怎么查
常见于手写二分时下标计算错误,尤其在 right 缩小时没同步检查边界。典型诱因:
- 用
while (left 却在循环内写 <code>right = mid - 1,导致right变成-1后仍进入下轮,访问nums[-1] - 初始化
right = nums.size()(开区间习惯)却用闭区间逻辑,造成越界 - 没处理空数组:
nums.empty()时直接访问nums[0]或nums.back()
防御性写法:开头加 if (nums.empty()) return 0;(按题意返回默认值),所有下标访问前不假设非空。
Python 用户别直接套用 C++ 思路
C++ 的 vector 支持随机访问且无内置二分,所以手动实现是常态。但 Python 的 list 虽也支持 O(1) 索引,可你真没必要重写二分 —— 除非面试要求。实际项目中,更应关注是否真需要 O(log n):
- 如果数组极小(
元素),线性扫描 <code>min(nums)更快(无函数调用开销、CPU 预测友好) - 如果数据来自数据库或文件流,I/O 开销远大于计算,此时优化算法意义不大
- Python 的
bisect模块不直接支持旋转数组,硬套bisect_left会出错,别试
真正要警惕的,是把“理论上更快”当成“实际上更好”。二分的常数因子、缓存不友好、以及对重复值的脆弱性,在真实数据分布下未必赢过一行 min()。


















