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

LeetCode 153:比较 nums[mid] 与 nums[right],二分定位旋转点/最小值。

#resource / algorithm #type / howto #status / evergreen #source / leetcode #algo / binary-search #ds / array

[!info] related notes 算法面试题型 MOC 二分查找

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

题目

153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

题目特征

  • 原数组升序,发生旋转
  • 元素互不相同
  • 期望时间复杂度 O(log n)

组合起来基本就是:二分找旋转点 / 最小值。

思路

虽然数组整体不完全有序,但它可以看成:

  • 左边较大的一段 + 右边较小的一段

最小值就是右边这段的起点。

核心做法:在闭区间 [left, right] 上二分,比较 nums[mid]nums[right] 来判断最小值在哪一侧。

为什么和 nums[right] 比

right 永远是当前搜索区间的最右端。

  • 如果 nums[mid] < nums[right]:说明 mid..right 这段是有序的,最小值不在 mid 的右边,但 mid 可能就是最小值 => right = mid
  • 如果 nums[mid] > nums[right]:说明 mid 在左边较大那段,最小值一定在右边且不包含 mid => left = mid + 1

循环不变量

  • 最小值始终在 [left, right]
  • 每次循环都缩小区间
  • 最终 left == right,该位置即最小值

易错点

  • nums[mid] < nums[right] 时不能写 right = mid - 1(因为 mid 可能是最小值)
  • 最终返回 nums[left](此时 left == right
  • “闭区间”不等于“机械 ±1”,更新规则取决于 mid 能否被排除

代码(JavaScript)

var findMin = function(nums) {
  let left = 0;
  let right = nums.length - 1;

  while (left < right) {
    const mid = Math.floor((left + right) / 2);
    if (nums[mid] < nums[right]) {
      right = mid;      // mid 可能是最小值,保留
    } else {
      left = mid + 1;   // mid 不可能是最小值,排除
    }
  }

  return nums[left];
};

复杂度

  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

一句话总结

比较 nums[mid]nums[right]:若 nums[mid] < nums[right],最小值在左侧且包含 mid;否则在右侧且不包含 mid,不断收缩直到 left == right

和 33 题的区别

创建于 2026/3/16 更新于 2026/5/27