每日一题——二分法求旋转数组的最小数字

devtools/2025/1/23 16:58:58/

二分法求旋转数组的最小数字

    • 描述
      • 数据范围:
      • 要求:
    • 示例
      • 示例 1
      • 示例 2
    • 解题思路
    • 代码实现
    • 关键点解释
    • 举例分析
      • 示例 1:[3, 4, 5, 1, 2]
      • 示例 2:[3, 100, 200, 3]
    • 总结

描述

有一个长度为 n 的非降序数组,例如 [1, 2, 3, 4, 5],将它进行旋转,即把数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成 [3, 4, 5, 1, 2],或者 [4, 5, 1, 2, 3] 这样的。给定一个旋转数组,求数组中的最小值。

数据范围:

  • 1 ≤ n ≤ 10000
  • 数组中任意元素的值:0 ≤ val ≤ 10000

要求:

  • 时间复杂度O(logn)
  • 空间复杂度O(1)

示例

示例 1

输入:

[3, 4, 5, 1, 2]

返回值:

1

示例 2

输入:

[3, 100, 200, 3]

返回值:

3

解题思路

在这道题中,我们需要使用二分法来提高查找效率,从而将线性时间复杂度降低为对数级别。旋转数组的特性使得我们可以利用二分法,逐步缩小搜索范围。

算法流程

在这里插入图片描述

  1. 初始化:声明 leftright 双指针,分别指向数组的左右两端。
  2. 循环二分:设定中点 mid = (left + right) / 2,每次通过比较 nums[mid]nums[right] 来决定下一步搜索范围:
    • 如果 nums[mid] > nums[right],说明旋转点位于右半部分,最小值在 [mid + 1, right] 区间。
    • 如果 nums[mid] < nums[right],说明旋转点位于左半部分,最小值在 [left, mid] 区间。
    • 如果 nums[mid] == nums[right],无法判断旋转点位置,此时将 right-- 缩小范围。
  3. 返回最小值:当 left == right 时,跳出循环,此时 leftright 都指向旋转数组中的最小值。

代码实现

int minNumberInRotateArray(int* nums, int numsLen) {// 如果数组没有旋转,直接返回最左边的元素if (nums[0] < nums[numsLen - 1]) {return nums[0];}int left = 0, mid = 0, right = numsLen - 1;// 使用二分法查找最小值while (left < right) {mid = left + (right - left) / 2;  // 计算中点if (nums[mid] > nums[right]) {// mid在左侧有序部分,最小值在右边left = mid + 1;} else if (nums[mid] < nums[right]) {// mid在右侧有序部分,最小值在左边right = mid;} else {// nums[mid] == nums[right]时,无法判断最小值在哪一侧right--;}}return nums[left];  // 返回最小值
}

关键点解释

  1. 判断数组是否有序

    • 如果数组未旋转(即 nums[0] < nums[numsLen - 1]),直接返回最小值 nums[0]
  2. 二分法的核心判断条件

    • nums[mid] > nums[right]:旋转点在右侧,最小值在 [mid + 1, right]
    • nums[mid] < nums[right]:旋转点在左侧,最小值在 [left, mid]
    • nums[mid] == nums[right]:无法判断旋转点在左侧还是右侧,缩小右边界 right--
  3. 为什么要用 right-- 而不是 right = mid

    • nums[mid] == nums[right] 时,无法确定旋转点的位置,right-- 是为了收缩右边界,逐步缩小搜索范围,最终能够找到最小值。

举例分析

示例 1:[3, 4, 5, 1, 2]

  1. 初始时,left = 0right = 4
  2. 中点 mid = 2,比较 nums[mid] = 5nums[right] = 2,因为 nums[mid] > nums[right],说明旋转点在右边,更新 left = mid + 1 = 3
  3. 然后,left = 3right = 4,计算新的 mid = 3,比较 nums[mid] = 1nums[right] = 2,因为 nums[mid] < nums[right],说明最小值在左边,更新 right = mid = 3
  4. 此时 left = right = 3,跳出循环,返回 nums[left] = 1

示例 2:[3, 100, 200, 3]

  1. 初始时,left = 0right = 3
  2. 中点 mid = 1,比较 nums[mid] = 100nums[right] = 3,因为 nums[mid] > nums[right],更新 left = mid + 1 = 2
  3. 然后,left = 2right = 3,计算新的 mid = 2,比较 nums[mid] = 200nums[right] = 3,因为 nums[mid] > nums[right],更新 left = mid + 1 = 3
  4. 此时 left = right = 3,跳出循环,返回 nums[left] = 3

总结

其实这题整体上还是比较简单的。按照二分法的思路,其实还是比较好理解的。很快就能写出代码来,但是真正的难题是,如果遇到数组为[1,1,0,1,1,1]的情况,立刻就完蛋了。思考了半天,还是去参考了别人的代码。不太理解为什么用 right-- 而不是 right = mid
后来思考了下才理解,当 nums[mid] == nums[right] 时,我们无法确定 mid 和 right 哪个位置是有序的,因此只能将 right 向左移动一个位置。这是因为即使 mid 和 right 相等,right-- 仍然能保证范围逐渐缩小,最终能找到最小值。不理解为什么用right,而不是left。思考了半天,最后还是放弃了,背就完了。


http://www.ppmy.cn/devtools/152934.html

相关文章

考研408笔记之数据结构(三)——串

数据结构&#xff08;三&#xff09;——串 1. 串的定义和基本操作 本节内容很少&#xff0c;重点是串的模式匹配&#xff0c;所以对于串的定义和基本操作&#xff0c;我就简单提一些易错点。另外&#xff0c;串也是一种特殊的线性表&#xff0c;只不过线性表是可以存储任何东…

RK3568笔记七十六:使用V4L2框架录制MP4视频保存到本地

若该文为原创文章,转载请注明原文出处。 录制MP4使用的是ffmpeg,如何编译自行处理。 使用的是正点原子的RK3568测试,其他板子自行调试。 一、程序功能介绍 说明: 程序参考FFMPEG提供的例子程序muxing.c进行修改。 功能介绍: 程序里目前有一个子线程和一个主线程,子线程…

SSM项目本地Tomcat部署

目录 1、打包 2、部署在本地Tomcat上 3、运行tomcat&#xff08;startup&#xff09; 1、打包 在生命周期中&#xff0c;完成打包。 注意&#xff1a;打包时会测试&#xff0c;测试时可能会测试根据id删除。第二次的测试就会出错&#xff0c;导致打包失败。 从target目录下…

【趣学SQL】第三章:数据处理与管理 3.1数据清洗技术——给数据库做“数据SPA“的魔幻之旅

第三章&#xff1a;数据处理与管理 3.1 数据清洗技术——给数据库做"数据SPA"的魔幻之旅 欢迎来到「数据库美容院」&#xff01;今天我们将化身"数据美容师"&#xff0c;用一家虚拟网红餐厅的翻车案例&#xff0c;教你如何把脏乱差的原始数据变成清爽整洁…

网站HTTP改成HTTPS

您不仅需要知道如何将HTTP转换为HTTPS&#xff0c;还必须在不妨碍您的网站自成立以来建立的任何搜索排名权限的情况下进行切换。 为什么应该从HTTP转换为HTTPS&#xff1f; 与非安全HTTP于不同&#xff0c;安全域使用SSL&#xff08;安全套接字层&#xff09;服务器上的加密代…

nuxt3项目打包部署到服务器后配置端口号和开启https

nuxt3打包后的项目部署相对于一般vite打包的静态文件部署要稍微麻烦一些&#xff0c;还有一个主要的问题是开发环境配置的.env环境变量在打包后部署时获取不到&#xff0c;具体的解决方案可以参考我之前文章 nuxt3项目打包后获取.env设置的环境变量无效的解决办法。 这里使用的…

Java菜鸟养成计划(java基础)--java数据类型

数据类型 1、什么是数据类型&#xff1f;2、java中的数据类型有哪些&#xff1f;3、基本数据类型有哪些&#xff1f;3.1、布尔类型&#xff08;boolean&#xff09;3.2、字符类型3.3、整形&#xff08;默认int&#xff09;3.4、浮点型【默认double】小数3.5、基本数据类型之间的…

【力扣】2.两数相加

题目 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都不会…