图解题库 / 二分查找 · 找最小

153. 寻找旋转排序数组中的最小值

中等 含交互动画

学完这道你应该能: 说清它为什么用「找最小」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

题目描述

一个升序数组在某个点旋转过(比如 [0,1,2,4,5,6,7] 转成 [4,5,6,7,0,1,2]),找出里面最小的元素。

nums = [4,5,6,7,0,1,2]
输出 = 0

思路解析

一个个比当然能找到,可这么干就跟没排序、没旋转一样,白瞎了题目摆在你面前的有序条件。

关键一招:mid 比右端点还大,说明 mid 还待在「高的那段」,最小值在它右边;否则最小在左边(mid 自己也可能就是)。

循环条件是 l < r(不是 <=),一路收到 l 和 r 重合,那个位置就是最小值。

l=0, r=6:mid=3 是 7,比右端点 2 还大,说明前面这截都是「高的」,最小一定在右边,l 跳到 4。

l=4, r=6:看 mid=5 是 1,比右端点 2 小,最小值在它左边、或就是它自己,所以 r 收到 5。注意是 r=mid,不是 mid-1。

l=4, r=5:再比一次,mid=4 是 0,还是比右端点小,r 收到 4。现在 l 和 r 都指向 4 了。

l=4, r=4:l 和 r 撞一起,循环结束。下标 4 的 0 就是最小值,全程没扫整个数组。

旋转找最小就记一句:nums[mid] 比 nums[r] 大就往右,否则往左收,循环到 l==r

参考代码(Python)

Python
1def findMin(nums):
2    l, r = 0, len(nums) - 1
3    while l < r:                 # 注意是 <,收敛到一个数
4        mid = (l + r) // 2
5        if nums[mid] > nums[r]:  # mid 在高段
6            l = mid + 1          # 最小在右半
7        else:
8            r = mid              # 最小在左半(含 mid)
9    return nums[l]

复杂度分析

  • 时间复杂度:O(log n) —— 每轮砍一半
  • 空间复杂度:O(1) —— 俩指针

套路模板

骨架就这几行。为啥跟右端点比、不跟左端点?因为跟左端点比会有歧义,跟右端点比永远干净——这是这题的命门。

Python
1l, r = 0, n - 1
2while l < r:
3    mid = (l + r) // 2
4    if nums[mid] > nums[r]: l = mid + 1
5    else: r = mid
6return nums[l]   # l == r 即最小值下标

易错点

  • 和 nums[l] 比 → ✅ 和 nums[r] 比(跟左端点比会有歧义(mid 可能比 l 大但仍在高段),跟右端点比才能干净地判方向)
  • nums[mid]>nums[r] 不成立时 r = mid-1 → ✅ r = mid(不减 1)(mid 自己可能就是最小值,减 1 会把答案跳过去)
  • while l <= r → ✅ while l < r(这是收敛找位置,l<=r 配 r=mid 会原地死循环)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →74. 搜索二维矩阵 ← 返回题库