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

中等 含交互动画

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

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

一个升序数组在某点旋转过(如 [0,1,2,4,5,6,7] 转成 [4,5,6,7,0,1,2]),找出其中的最小值

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

思路解析

挨个比当然能找到最小,可那是 O(n),白白浪费了「旋转前本来有序」。题目把有序明牌摆这了,得用二分把它砍到 O(log n)。

转折:最小值就是旋转点。怎么二分定位它?拿 nums[mid] 和右端点 nums[r] 比——这是不变量:若 nums[mid] > nums[r],说明从 mid 到 r 中间有断崖,最小值在 mid 右边(l=mid+1);若 nums[mid] < nums[r],说明 mid 到 r 已经是连续升序,最小值在 mid 或它左边(r=mid,别丢 mid)。为什么不和 nums[l] 比?因为左半整段可能都比最小值大,比左端判不出方向。

准备 · 闭区间 [0,6]:搜索范围是整个数组,l=0、r=6。比较的「锚」永远是当前的右端 nums[r]。

第 1 轮 · 取 mid:中点 mid=3,nums[3] = 7。和右端点 nums[6]=2 比。

第 1 轮 · 判断(负例分支):7 > 2,说明从 mid 走到 r 中间一定掉过崖(旋转点在右半),最小值在 mid 右边,且 mid 本身肯定不是最小。

第 1 轮 · 收缩:l 跳到 mid+1=4,左半 [4,5,6,7](灰)整段丢掉——这半里没有最小值。范围缩到 [4, 6]。

第 2 轮 · 取 mid:范围 [4,6],新中点 mid=5,nums[5] = 1。继续和右端 nums[6]=2 比。

第 2 轮 · 判断:1 < 2,说明从 mid 到 r 是连续升序(没掉崖),那这段最小的就在 mid 这头。最小值在 mid 或它左边,mid 可能就是答案。

第 2 轮 · 收缩:r 收到 mid=5(不是 mid−1,因为 mid 自己可能就是最小)。下标 6 丢掉,范围 [4, 5]。

第 3 轮 · 取 mid:范围 [4,5],mid=4,nums[4] = 0。和右端 nums[5]=1 比。

第 3 轮 · 收缩 → l==r:0 < 1,最小值在 mid 或其左,r 收到 4。现在 l == r == 4,区间只剩一个,循环结束。

答案:l 和 r 撞在下标 4,nums[4] = 0 就是最小值。每轮砍一半,O(log n) 搞定。

旋转找最小,记死一句:和右端点比。大于则断崖(最小值)在右,否则在左含 mid。和 nums[l] 比会判错,因为左半可能整段偏大。

参考代码(Python)

Python
1def findMin(self, nums):
2    l, r = 0, len(nums) - 1         # 闭区间 [l, r]
3    while l < r:                    # 注意是 < 不是 <=
4        mid = l + (r - l) // 2
5        if nums[mid] > nums[r]:     # 和右端比,断崖在右
6            l = mid + 1            # 最小值在 mid 右边
7        else:                      # nums[mid] < nums[r],已升序
8            r = mid                # 最小值在 mid 或其左,别丢 mid
9    return nums[l]                  # l==r 时即最小值

复杂度分析

  • 时间复杂度:O(log n) —— 每轮把区间砍掉一半
  • 空间复杂度:O(1) —— 只用 l、r、mid 三个变量

套路模板

骨架记牢:while l < r、和 nums[r] 比、大于则 l=mid+1 否则 r=mid。LC154(含重复)、LC33(旋转找 target)都是它的近亲。

Python
1l, r = 0, len(nums) - 1
2while l < r:
3    mid = l + (r - l) // 2
4    if nums[mid] > nums[r]:
5        l = mid + 1        # 最小在右
6    else:
7        r = mid            # 最小在左(含 mid)
8return nums[l]

易错点

  • 错误写法:拿 nums[mid] 和 nums[l] 比正确写法:和 nums[r] 比(左半可能整段都比最小值大,和左端比判不出最小值在哪边;只有和右端比才能稳定定位断崖)
  • 错误写法:nums[mid] < nums[r] 时写 r = mid - 1正确写法:r = mid(不减 1)(mid 自己可能就是最小值,减 1 会把它丢掉,结果偏大或越界)
  • 错误写法:循环写成 while l <= r正确写法:while l < r(本题靠 l==r 收尾返回 nums[l];用 <= 且 r=mid 不减会在 l==r 时死循环)

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

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