【每日算法】LeetCode 153. 寻找旋转排序数组中的最小值

对前端开发者而言,学习算法绝非为了"炫技"。它是你从"页面构建者"迈向"复杂系统设计者"的关键阶梯。它将你的编码能力从"实现功能"提升到"设计优雅、高效解决方案"的层面。从现在开始,每天投入一小段时间,结合前端场景去理解和练习,你将会感受到自身技术视野和问题解决能力的质的飞跃。------ 算法:资深前端开发者的进阶引擎

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

1. 题目描述

假设一个按照升序排列的数组在某个未知的"旋转点"上进行了旋转(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2])。给定一个 互不相同 元素的旋转排序数组 nums,要求找出并返回数组中的 最小元素

示例 1:

复制代码
输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5],旋转后最小值是 1。

示例 2:

复制代码
输入:nums = [4,5,6,7,0,1,2]
输出:0

示例 3:

复制代码
输入:nums = [11,13,15,17]
输出:11
解释:数组未旋转或旋转点为首元素。

提示:

  • n == nums.length
  • 1 <= n <= 5000
  • -5000 <= nums[i] <= 5000
  • nums 中所有元素 互不相同
  • 设计时间复杂度为 O(log n) 的算法

2. 问题分析

对于一个升序排序数组旋转后,它由 两个递增的子数组 组成:第一个子数组的元素都大于第二个子数组的元素,且最小值是第二个子数组的第一个元素。例如,[4,5,6,7,0,1,2] 中,第一个子数组为 [4,5,6,7],第二个为 [0,1,2],最小值为 0

关键点在于:

  • 如果数组未旋转(或旋转点在首元素),最小值是第一个元素。
  • 由于数组部分有序,可以利用 二分查找 来优化搜索,避免 O(n) 的遍历。

3. 解题思路

3.1 思路一:暴力遍历法

直接遍历整个数组,维护一个变量记录最小值。时间复杂度 O(n),空间复杂度 O(1)。简单但未利用数组特性,不是最优解。

3.2 思路二:二分查找法(最优解)

利用数组的 部分有序性,通过比较中间元素和右端点元素,判断最小值所在区间:

  • 如果 nums[mid] > nums[right]:最小值在右半部分(因为右半部分是更小的子数组),搜索区间更新为 [mid + 1, right]
  • 否则:最小值在左半部分或 mid 处,搜索区间更新为 [left, mid]

这个过程将时间复杂度降至 O(log n),空间复杂度 O(1),是最优解。

4. 各思路代码实现

4.1 暴力遍历法实现

javascript 复制代码
function findMin(nums) {
    let min = nums[0];
    for (let i = 1; i < nums.length; i++) {
        if (nums[i] < min) {
            min = nums[i];
        }
    }
    return min;
}

4.2 二分查找法实现

javascript 复制代码
function findMin(nums) {
    let left = 0;
    let right = nums.length - 1;
    while (left < right) {
        let mid = Math.floor((left + right) / 2);
        if (nums[mid] > nums[right]) {
            // 最小值在右半部分
            left = mid + 1;
        } else {
            // 最小值在左半部分或 mid 处
            right = mid;
        }
    }
    return nums[left]; // 当 left == right 时,找到最小值
}

5. 各实现思路的复杂度、优缺点对比表格

思路 时间复杂度 空间复杂度 优点 缺点
暴力遍历法 O(n) O(1) 代码简单易懂,适用于小数组或对性能要求不高的场景 未利用数组有序性,效率低,不满足 O(log n) 要求
二分查找法 O(log n) O(1) 高效,利用部分有序性,满足题目要求 逻辑稍复杂,需注意边界条件

最优解总结:二分查找法在时间和空间上均最优,是解决此类旋转排序数组问题的标准方法。

相关推荐
Lee川1 小时前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i3 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有4 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有4 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫5 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫5 小时前
Handler基本概念
面试
Gorway5 小时前
解析残差网络 (ResNet)
算法
Wect5 小时前
浏览器缓存机制
前端·面试·浏览器
拖拉斯旋风5 小时前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect5 小时前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript