153. 寻找旋转排序数组中的最小值
一、算法逻辑(逐步通顺讲解每一步思路)
题目背景是:
一个原本升序排列的数组 nums
被旋转了一次,即它被某个位置劈开后两部分拼接。例如:
python
原数组: [1, 2, 3, 4, 5]
旋转后: [4, 5, 1, 2, 3]
我们需要找到其中最小的元素 ,并且数组中无重复元素。
这段算法使用的是一种略带技巧的「偏左二分写法」,与传统的 left=0, right=n-1
不同,用的是:
python
left = -1
right = n - 1
✅ 1️⃣ 定义搜索区间
-
left = -1
:虚拟出一个位置在数组之外; -
right = len(nums) - 1
:最后一个真实下标; -
搜索区间为
(left, right]
,即右闭左开。
✅ 2️⃣ 二分查找逻辑
每次计算中点 mid = (left + right) // 2
,然后根据与 nums[-1]
(末尾元素)的关系进行判断:
-
若
nums[mid] < nums[-1]
,说明最小值一定在左边(含 mid),收缩右边界right = mid
; -
否则说明最小值在右边(不含 mid),排除左侧区间,更新
left = mid
。
这样做的核心思想是:
把数组划分为两个区间:大于等于最小值的一段 和 严格小于最小值的一段,通过与末尾元素对比快速定位边界。
✅ 3️⃣ 循环结束
当 left + 1 == right
时,循环终止,right
就指向整个数组的最小值位置。
✅ 4️⃣ 返回结果
返回 nums[right]
即为最终结果。
二、核心点总结
✅ 使用末尾元素 nums[-1]
作为分界线 ,实现更稳定的二分判断逻辑;
✅ 区间设置为 (left, right]
,使用 left = -1
是为了避免特殊判断头尾边界,写法简洁统一 ;
✅ 属于 偏左二分查找技巧 ,尤其适用于搜索单调转折点 的题;
✅ 终止条件是 left + 1 == right
,使得最终 right
恰好指向最小元素下标。
这是一种非常"干净"的二分思路,在 LeetCode 上用于 rotated array 系列题非常常见。
python
class Solution:
def findMin(self, nums: List[int]) -> int:
left, right = -1, len(nums)-1
while left+1<right:
mid = (left+right)//2
if nums[mid]<nums[-1]:
right = mid
else:
left = mid
return nums[right]
三、时间复杂度分析
每次将搜索区间砍半,总共最多 log n
次比较:
✅ 时间复杂度:O(log n)
四、空间复杂度分析
仅使用常数个辅助变量:
✅ 空间复杂度:O(1)
✅ 总结一句话
这段算法使用「与末尾元素比较 + 偏左二分」策略,巧妙地定位旋转数组中的最小值,时间复杂度 O(log n),空间复杂度 O(1),逻辑简洁、边界统一,是处理旋转数组查找问题的极佳模板。