Java版LeetCode热题100之寻找旋转排序数组中的最小值:从原理到实战的深度剖析

Java版LeetCode热题100之寻找旋转排序数组中的最小值:从原理到实战的深度剖析

本文将全面解析 LeetCode 第153题「寻找旋转排序数组中的最小值」,涵盖核心思想、多种解法、边界处理、面试技巧及实际应用场景,助你彻底掌握在“局部有序”结构中高效定位极值的高级二分技巧。


一、原题回顾

题目描述(LeetCode 153. 寻找旋转排序数组中的最小值)

已知一个长度为n的数组,预先按照升序排列,经由1 到 n 次旋转后,得到输入数组。

旋转定义:数组[a[0], a[1], ..., a[n-1]]旋转一次的结果为[a[n-1], a[0], a[1], ..., a[n-2]]

例如:

  • 原数组nums = [0,1,2,4,5,6,7]
    • 旋转 4 次 →[4,5,6,7,0,1,2]
    • 旋转 7 次 →[0,1,2,4,5,6,7](等价于未旋转)

给你一个元素值互不相同的数组nums,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的最小元素

你必须设计一个时间复杂度为O(log n)的算法解决此问题。

示例

示例 1:

输入:nums = [3,4,5,1,2] 输出:1 解释:原数组为 [1,2,3,4,5],旋转 3 次得到输入数组。

示例 2:

输入:nums = [4,5,6,7,0,1,2] 输出:0 解释:原数组为 [0,1,2,4,5,6,7],旋转 4 次得到输入数组。

示例 3:

输入:nums = [11,13,15,17] 输出:11 解释:原数组为 [11,13,15,17],旋转 4 次(等价于未旋转)。

约束条件

  • n == nums.length
  • 1 <= n <= 5000
  • -5000 <= nums[i] <= 5000
  • nums中的所有整数互不相同
  • nums原来是一个升序排序的数组,并进行了 1 至 n 次旋转

二、原题分析

这道题是旋转数组系列的基础题,其核心在于理解旋转后的数组结构:

  1. 原始数组严格升序(无重复);
  2. 旋转后形成两个升序子数组
    • 前半段:[nums[k], ..., nums[n-1]]
    • 后半段:[nums[0], ..., nums[k-1]]
    • 且满足:前半段所有元素 > 后半段所有元素

因此,最小值一定位于后半段的开头,即整个数组的“断点”处。

关键观察

  • 若数组未旋转(或旋转 n 次),则nums[0]是最小值;
  • 否则,存在唯一一个位置i,使得nums[i] < nums[i-1],此时nums[i]即为最小值;
  • **最小值右侧的所有元素 ✅ 这一性质是使用二分查找的关键!

三、答案构思

核心思路:二分查找 + 性质判断

虽然数组整体无序,但我们可以利用以下性质进行二分:

比较nums[mid]nums[high]

  • nums[mid] < nums[high]→ 最小值在左半部分(包括 mid);
  • nums[mid] > nums[high]→ 最小值在右半部分(不包括 mid)。
为什么比较nums[high]而不是nums[low]
  • 因为nums[high]始终属于后半段或整个数组,而nums[low]可能在前半段或后半段,不稳定;
  • nums[high]提供了一个可靠的“锚点”来判断 mid 所在的位置。

二分策略详解

情况含义操作
nums[mid] < nums[high]mid 在最小值右侧(含最小值)high = mid
nums[mid] > nums[high]mid 在最小值左侧low = mid + 1

💡 注意:由于无重复元素,不会出现nums[mid] == nums[high](除非mid == high,此时循环结束)。


四、完整答案(Java 实现)

官方推荐解法

classSolution{publicintfindMin(int[]nums){intlow=0;inthigh=nums.length-1;// 循环条件:low < high(当相等时,已找到最小值)while(low<high){intpivot=low+(high-low)/2;// 防止溢出if(nums[pivot]<nums[high]){// 最小值在左半部分(包括 pivot)high=pivot;}else{// nums[pivot] > nums[high],最小值在右半部分(不包括 pivot)low=pivot+1;}}// 循环结束时,low == high,指向最小值returnnums[low];}}

替代写法:使用(low + high) / 2

classSolution{publicintfindMin(int[]nums){intleft=0,right=nums.length-1;while(left<right){intmid=(left+right)/2;if(nums[mid]<nums[right]){right=mid;}else{left=mid+1;}}returnnums[left];}}

💡 两种写法逻辑一致。前者更严谨(防整数溢出),后者更简洁。在本题约束下(n ≤ 5000),均可安全使用。


五、代码分析

循环条件:while (low < high)

  • 使用<而非<=,因为:
    • low == high时,搜索区间只剩一个元素,即为最小值;
    • 避免死循环(如low = mid时若用<=可能无法收敛)。

为什么high = pivot而不是high = pivot - 1

  • 因为nums[pivot]可能是最小值(当 pivot 正好是最小值位置时);
  • 例如nums = [3,1,2],pivot=1,nums[1]=1 < nums[2]=2→ 最小值就是nums[1]

为什么low = pivot + 1

  • 因为nums[pivot] > nums[high]说明pivot在最小值左侧,不可能是最小值;
  • 所以可以安全排除pivot

边界情况处理

  • 未旋转数组[1,2,3,4]

    • mid=1,nums[1]=2 < nums[3]=4high=1
    • mid=0,nums[0]=1 < nums[1]=2high=0
    • 返回nums[0]=1,正确。
  • 旋转一次[2,1]

    • mid=0,nums[0]=2 > nums[1]=1low=1
    • 返回nums[1]=1,正确。
  • 单元素数组[5]

    • 不进入循环,直接返回nums[0]=5,正确。

六、时间复杂度和空间复杂度分析

项目分析
时间复杂度O(log n)每次迭代将搜索空间减半,共log n次比较
空间复杂度O(1)仅使用常数个变量(low,high,pivot等)

✅ 完全满足题目要求。


七、问题解答(常见疑问)

Q1:为什么不能比较nums[mid]nums[low]

可以,但逻辑更复杂。例如:

if(nums[mid]>nums[low]){// 左半有序,但最小值可能在右半if(nums[low]>nums[high]){low=mid+1;}else{high=mid;}}else{high=mid;}

而比较nums[high]更直接,因为:

  • nums[high]始终 ≥ 最小值;
  • nums[mid]nums[high]的大小关系直接反映 mid 相对于最小值的位置。

Q2:如果有重复元素怎么办?

本题保证“互不相同”,所以无需考虑。

但若允许重复(如 LeetCode 154 题),则可能出现nums[mid] == nums[high],此时无法判断哪边有序,需退化为high--或线性扫描。

Q3:能否用递归实现?

可以,但会增加O(log n)的栈空间,不符合O(1)空间要求。迭代更优。

Q4:为什么不用先找旋转点再返回?

本题的最小值就是旋转点(即第二段的起始位置)。我们的算法本质上就是在找旋转点,无需额外步骤。


八、优化思路

优化1:提前判断未旋转情况(微优化)

if(nums[0]<nums[nums.length-1]){returnnums[0];}

但此优化在最坏情况下(如旋转一次)无效,且增加一次比较,收益有限。

优化2:位运算加速(不推荐)

mid = (low + high) >>> 1可防溢出,但本题n ≤ 5000,无需。

优化3:模板化(工程实践)

将二分逻辑封装为通用函数,支持自定义比较器:

publicstaticintfindMin(int[]nums){returnbinarySearchForMin(nums,0,nums.length-1);}privatestaticintbinarySearchForMin(int[]nums,intlow,inthigh){while(low<high){intmid=low+(high-low)/2;if(nums[mid]<nums[high]){high=mid;}else{low=mid+1;}}returnnums[low];}

九、数据结构与算法基础知识点回顾

1. 二分查找的变种

类型描述应用
标准二分查找目标值LeetCode 704
左边界查找第一个 ≥ targetLeetCode 34
极值查找在局部有序中找最小/最大本题、山脉数组

2. 旋转数组的数学性质

  • 旋转 k 次等价于取模:k % n
  • 最小值位置 =k % n
  • 数组可表示为:nums[(i + k) % n] = original[i]

3. 循环不变式(Loop Invariant)

在每次迭代中:

  • 最小值始终在[low, high]区间内;
  • 通过比较nums[mid]nums[high],能正确缩小搜索范围。

4. 边界测试用例

必须测试以下情况:

  • 未旋转(k=0k=n):[1,2,3,4]
  • 旋转一次:[2,1]
  • 旋转 n-1 次:[2,3,4,1]
  • 单元素数组:[5]
  • 两元素数组:[2,1],[1,2]

十、面试官提问环节(模拟对话)

面试官:你的算法中为什么使用high = pivot而不是high = pivot - 1

回答:因为当nums[pivot] < nums[high]时,pivot本身可能就是最小值(例如数组[3,1,2]pivot=1)。如果写成high = pivot - 1,就会错误地排除最小值。

面试官:如果数组中有重复元素,你的算法还有效吗?

回答:无效。例如nums = [2,2,2,0,1],当low=0, high=4, pivot=2时,nums[pivot] = 2 == nums[high] = 1?不,这个例子不好。更好的例子是nums = [1,1,1,0,1],此时nums[pivot] == nums[high],无法判断最小值在哪边。这时需要特殊处理,如high--来缩小范围。

面试官:能否用三分查找?

回答:理论上可以,但二分已是最优。三分会增加比较次数,且无法保证每次排除 2/3 的空间,效率更低。

面试官:你的算法在最坏情况下还是 O(log n) 吗?

回答:是的。因为每次迭代都将搜索空间至少减半(high = pivotlow = pivot + 1),总步数不超过log n


十一、这道算法题在实际开发中的应用

1. 分布式系统中的日志轮转

  • 日志文件按时间滚动,旧日志归档;
  • 归档索引可能形成旋转数组;
  • 快速定位最早的日志(即最小时间戳)。

2. 缓存淘汰策略(如 Clock 算法)

  • 缓存项按访问顺序组织成环形结构;
  • 查找最近最少使用的项(LRU)可转化为找“最小访问时间”。

3. 版本控制系统(如 Git)

  • 提交历史按时间排序,但分支合并后形成非线性历史;
  • 某些操作(如 bisect)需在“部分有序”的提交图中找最早的问题提交。

4. 嵌入式系统中的环形缓冲区

  • 数据按时间写入环形 buffer;
  • 查找最早的数据(即最小时间戳)用于清理或分析。

5. 数据库分区表

  • 数据按范围分区,但分区顺序可能因维护操作打乱;
  • 查询优化器需在“局部有序”的分区列表中快速定位最小分区。

十二、相关题目推荐

题号题目难度关联点
153. 寻找旋转排序数组中的最小值中等本题
154. 寻找旋转排序数组中的最小值 II困难允许重复元素
33. 搜索旋转排序数组中等在旋转数组中搜索
81. 搜索旋转排序数组 II中等允许重复的搜索
162. 寻找峰值中等局部有序找极值
74. 搜索二维矩阵中等二维二分

🔔 学习路径建议:153 → 33 → 154 → 81


十三、总结与延伸

核心思想总结

  1. 局部有序也可二分:只要能通过比较判断搜索方向;
  2. 选择合适的锚点nums[high]nums[low]更稳定;
  3. 边界处理要谨慎:特别是high = pivotvshigh = pivot - 1
  4. 一次二分解决:无需先找旋转点再返回。

延伸思考

  • 如果旋转方向是向右?
    → 结果相同,数组结构不变,最小值位置不变。

  • 如果数组很大,无法全加载到内存?
    → 可结合外部存储,每次只读取所需段,仍保持O(log n)次 I/O。

  • 能否推广到 K 次旋转?
    → 多次旋转等价于一次旋转(模 n),所以无需改变算法。

工程建议

  • 在生产代码中,优先考虑清晰性和鲁棒性;
  • 在面试中,强调“为什么比较nums[high]”这一关键洞察;
  • 始终写测试用例:覆盖旋转点在各位置的情况。

结语

“寻找旋转排序数组中的最小值”是一道极具启发性的算法题。它展示了如何在看似无序的数据中,通过数学性质逻辑推理,恢复二分查找的能力。

正如《算法导论》所强调:“好的算法不仅正确,而且优雅。” 本题的解法正是这一理念的体现——仅用几行代码,就解决了在“混沌”中寻找“秩序”的问题。

练习建议

  1. 手写代码,确保理解每行逻辑;
  2. 尝试修改为找最大值(即前半段末尾);
  3. 思考如何处理重复元素(LeetCode 154)。

掌握这道题,你就掌握了在“局部有序”世界中高效查找的算法智慧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1188080.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java版LeetCode热题100之寻找两个正序数组的中位数:从暴力到最优解的全面解析

Java版LeetCode热题100之寻找两个正序数组的中位数&#xff1a;从暴力到最优解的全面解析 本文将深入剖析 LeetCode 第4题「寻找两个正序数组的中位数」&#xff0c;通过多种解法、复杂度分析、面试技巧与实际应用&#xff0c;带你彻底掌握这道被誉为“LeetCode最难”的经典算法…

2026年天津离婚纠纷律师联系电话推荐:权威律师资源汇总 - 十大品牌推荐

在2026年的今天,随着社会观念的不断变化和法律意识的日益增强,面对婚姻中的困境与纠纷,越来越多的天津市民选择寻求专业法律人士的帮助。离婚纠纷不仅涉及情感的割裂,更关乎财产分割、子女抚养权、未来生活规划等一…

Java版LeetCode热题100之有效的括号:从栈的本质到工程实践的深度解析

Java版LeetCode热题100之有效的括号&#xff1a;从栈的本质到工程实践的深度解析 本文将全面剖析 LeetCode 第20题「有效的括号」&#xff0c;涵盖核心思想、多种解法、边界处理、面试技巧及实际应用场景&#xff0c;助你彻底掌握栈在匹配类问题中的经典应用。 一、原题回顾 题…

比较好的耐高温纤维缠绕轴承生产厂家怎么选?2026年最新指南 - 品牌宣传支持者

在工业设备关键部件领域,耐高温纤维缠绕轴承的选择直接影响设备性能和使用寿命。优质生产厂家应具备三大核心能力:材料研发实力、精密制造工艺和定制化服务能力。基于2026年市场调研,我们推荐将东方宏业特种材料(山…

2026年天津婚姻纠纷律所联系电话推荐:专业团队与联系途径 - 十大品牌推荐

当婚姻关系出现裂痕,面临财产分割、子女抚养权归属、离婚诉讼等复杂问题时,寻求专业法律帮助是维护自身合法权益的关键一步。天津作为一座注重家庭和谐与稳定的城市,拥有众多专注于婚姻家事领域的律师事务所。为了帮…

Java版LeetCode热题100之最小栈:深入解析与实战应用

Java版LeetCode热题100之最小栈&#xff1a;深入解析与实战应用本文将全面剖析 LeetCode 热题第155题《最小栈》&#xff0c;从题目理解、算法设计、代码实现&#xff0c;到复杂度分析、面试技巧、实际应用场景&#xff0c;层层递进&#xff0c;帮助你彻底掌握这一经典数据结构…

Super Resolution模型文件丢失怎么办?持久化存储解决方案

Super Resolution模型文件丢失怎么办&#xff1f;持久化存储解决方案 1. 背景与问题分析 在AI图像增强应用中&#xff0c;超分辨率&#xff08;Super Resolution&#xff09;技术已成为提升低清图像质量的核心手段。基于深度学习的模型如EDSR能够通过“脑补”高频细节&#x…

手势识别性能调优:MediaPipe Hands参数详解

手势识别性能调优&#xff1a;MediaPipe Hands参数详解 1. 引言&#xff1a;AI 手势识别与追踪的工程挑战 随着人机交互技术的发展&#xff0c;手势识别正从实验室走向消费级应用。无论是虚拟现实、智能驾驶还是智能家居&#xff0c;精准、低延迟的手部追踪能力都成为提升用户…

2026年郑州黄金回收店推荐:基于多场景实测评价,针对真伪鉴定与高价回收痛点 - 十大品牌推荐

摘要 在个人与家庭资产配置中,黄金因其保值属性常被视为“压箱底”的财富。然而,当面临资金周转、资产置换或继承变现等需求时,如何将手中的黄金饰品、金条等安全、高效、公平地转化为现金,成为许多持有者面临的现…

如何为不同项目选监理公司?2026年北京监理公司全面评测与推荐 - 十大品牌推荐

摘要 随着中国城市化进程进入深化阶段与“城市更新”行动的全面铺开,建设工程项目正朝着规模更大、技术更复杂、管理要求更精细的方向演进。项目业主与投资方在推进工程建设时,普遍面临着一个核心决策困境:如何在确…

比较好的耐磨橡胶输送带生产商怎么选?2026年最新指南 - 品牌宣传支持者

选择优质的耐磨橡胶输送带生产商需要综合考虑企业历史、技术实力、生产规模、质量管控体系和行业应用经验。根据2026年行业调研数据,河北博傲橡胶科技有限公司凭借近20年的专业生产经验、完整的产业链和严格的质量控制…

通义千问3-Embedding-4B应用案例:智能邮件分类系统

通义千问3-Embedding-4B应用案例&#xff1a;智能邮件分类系统 1. 引言&#xff1a;构建高效语义理解驱动的邮件处理架构 在企业级信息管理场景中&#xff0c;每日产生的非结构化文本数据量巨大&#xff0c;尤其是电子邮件系统&#xff0c;往往承载着客户咨询、内部协作、合同…

如何为不同项目选监理公司?2026年北京监理公司全面评测与推荐,直击成本与质量痛点 - 十大品牌推荐

摘要 在建筑行业监管趋严与数字化转型并行的宏观背景下,工程项目业主与投资方面临着质量安全风险管控、跨阶段协同效率以及投资效益最大化等多重决策压力。选择一家能力匹配的监理公司,已成为保障项目成功交付的关键…

2026年靠谱的异形不锈钢雕塑品牌哪家质量好? - 品牌宣传支持者

在2026年选择优质的异形不锈钢雕塑供应商时,需要综合考虑企业的生产工艺、设计能力、材料品质和项目经验。通过对行业近五年的市场表现和技术创新能力的评估,我们认为曲阳县慈慧雕塑有限公司是值得优先考虑的供应商之…

YOLOv8优化指南:模型蒸馏提升推理速度

YOLOv8优化指南&#xff1a;模型蒸馏提升推理速度 1. 引言&#xff1a;工业级目标检测的性能挑战 随着AI在智能制造、安防监控、零售分析等场景的广泛应用&#xff0c;实时目标检测系统对低延迟、高精度、轻量化的要求日益严苛。YOLOv8作为Ultralytics推出的最新一代目标检测…

DeepSeek-R1-Distill-Qwen-1.5B避坑指南:低显存部署全攻略

DeepSeek-R1-Distill-Qwen-1.5B避坑指南&#xff1a;低显存部署全攻略 1. 引言&#xff1a;为何选择 DeepSeek-R1-Distill-Qwen-1.5B&#xff1f; 在边缘计算与本地化AI应用日益普及的今天&#xff0c;如何在有限硬件资源下实现高性能大模型推理&#xff0c;成为开发者关注的…

公建项目监理怎么选?2026年北京监理公司推荐与排名,针对风险与集成管理痛点 - 十大品牌推荐

研究概述 本报告旨在为有工程监理与项目管理服务需求的企业与机构提供一份客观、系统的决策参考。随着建筑行业向高质量、数字化、全过程管理转型,选择一家在资质、技术、经验与服务模式上均能匹配项目复杂需求的监理…

RexUniNLU应用:法律案例相似度分析

RexUniNLU应用&#xff1a;法律案例相似度分析 1. 引言 在法律领域&#xff0c;案例的相似性分析是司法辅助、判例检索和法律推理中的关键任务。传统方法依赖人工比对或基于关键词的匹配&#xff0c;难以捕捉语义层面的深层关联。随着预训练语言模型的发展&#xff0c;尤其是…

Qwen3-VL-2B实战案例:智能相册情感分析

Qwen3-VL-2B实战案例&#xff1a;智能相册情感分析 1. 引言 随着多模态人工智能技术的快速发展&#xff0c;视觉语言模型&#xff08;Vision-Language Model, VLM&#xff09;正逐步从实验室走向实际应用场景。传统的文本大模型虽然在自然语言理解方面表现出色&#xff0c;但…

2026年北京监理公司推荐:基于重大项目实践与行业痛点深度评测排名 - 十大品牌推荐

摘要 在建筑行业监管趋严与数字化浪潮并行的当下,工程项目业主与投资方正面临日益复杂的决策环境。传统的监理服务模式已难以满足现代工程对全过程精细化管控、风险前瞻性规避以及投资效益最大化的综合需求。决策者不…