Hot 100 --- 寻找旋转排序数组中的最小值
本文概览:本文讲解寻找旋转排序数组中的最小值的核心思路:两种方法——一次二分查找找旋转点,和一次二分查找直接找最小值
一、题目

二、题目分析
这题和前面的"搜索旋转排序数组"是同一类问题。
题目说数组经过旋转,每次旋转是把最后一位挪到最前面,不确定挪几次。但不管挪几次,最终结果都可以看作是左旋转了一次,即分成两段递增序列。
比如原来是 [0, 1, 2, 4, 5, 6, 7],旋转后可能变成 [4, 5, 6, 7, 0, 1, 2]。
旋转后的数组有两个特点:
- 分成两段递增序列:
[4, 5, 6, 7]和[0, 1, 2] - 最小值就是旋转点
题目要求时间复杂度 O(log n),显然要用二分查找。
有两种方法:
- 方法一:一次二分查找找旋转点(最小值就是旋转点)
- 方法二:一次二分查找直接找最小值(边找边比较)
思路概览
方法一:一次二分查找找旋转点
1 | public int findMin(int[] nums) { |
方法二:一次二分查找
1 | public int findMin(int[] nums) { |
思路简要说明:
方法一:
- 一次二分:找旋转点(最小值就是旋转点)
- 如果
nums[mid] > nums[right],说明旋转点在右边;否则在左边或就是 mid
方法二:
- 判断哪边有序:
nums[left] <= nums[mid]说明左边有序,否则右边有序 - 更新最小值:有序部分的第一个元素就是这部分的候选最小值
- 移动:去另一边继续找,因为最小值可能在另一边
三、思路详解
方法一:两次二分查找
第一步:找旋转点
旋转点就是数组中最小值的索引。
二分时,如果 nums[mid] > nums[right],说明旋转点在 mid 右边(因为右边有更小的值),更新 left = mid + 1。
否则旋转点在 mid 或 mid 左边,更新 right = mid。
循环结束时 left 就是旋转点。
第二步:比较两个候选最小值
旋转数组分成两段递增序列:
- 左边序列:
[0, pivot - 1],最小值是nums[0] - 右边序列:
[pivot, nums.length - 1],最小值是nums[pivot]
比较这两个值,取较小值。
完整执行过程
以 nums = [4, 5, 6, 7, 0, 1, 2] 为例:
第一次二分:找旋转点
1 | 初始:left=0, right=6 |
比较
1 | nums[0] = 4, nums[pivot] = nums[4] = 0 |
方法二:一次二分查找
第一步:判断哪边有序
和前一题一样,对于任意 mid:
- 如果
nums[left] <= nums[mid]:说明左边有序([left, mid]是递增的) - 否则:说明右边有序(
[mid, right]是递增的)
第二步:更新最小值
情况 1:左边有序
左边有序意味着 nums[left] 是左边这部分的最小值(因为递增)。
用 nums[left] 更新 min,然后去右边继续找(left = mid + 1),因为最小值可能在右边。
情况 2:右边有序
右边有序意味着 nums[mid] 是右边这部分的最小值(因为递增)。
用 nums[mid] 更新 min,然后去左边继续找(right = mid - 1),因为最小值可能在左边。
完整执行过程
以 nums = [4, 5, 6, 7, 0, 1, 2] 为例:
1 | 初始:left=0, right=6, min=4 |
再举一个例子,nums = [3, 4, 5, 1, 2]:
1 | 初始:left=0, right=4, min=3 |
四、总结
寻找旋转排序数组中的最小值有两种方法:
方法一:两次二分查找
- 第一次二分找旋转点
- 比较
nums[0]和nums[pivot],取较小值
方法二:一次二分查找
- 判断哪边有序
- 用有序部分的第一个元素更新最小值
- 去另一边继续找
两种方法的时间复杂度都是 O(log n),方法二代码更简洁,但方法一思路更直观。

