当前位置: 首页 > news >正文

Leetcode 搜索旋转排序数组

在这里插入图片描述
这段代码是用于解决LeetCode第33题“搜索旋转排序数组”的Java解法。以下是对该算法思想的中文解释:

算法思想

  1. 二分查找的基本思路

    • 由于数组是部分有序的(被旋转过),我们可以利用二分查找的思想,逐步缩小搜索范围。
    • 但是与普通的二分查找不同,这里的数组被旋转过,所以需要先判断当前数组的哪个部分是有序的,再决定如何更新搜索范围。
  2. 判断有序区间

    • 通过比较nums[left]nums[mid],我们可以确定左半部分或右半部分是否是有序的。
    • 如果nums[left] <= nums[mid],说明左半部分是有序的。
    • 如果nums[left] > nums[mid],说明右半部分是有序的。
  3. 确定目标值在哪个区间

    • 如果左半部分是有序的,且目标值targetnums[left]nums[mid]之间(即nums[left] <= target < nums[mid]),那么我们将搜索范围缩小到左半部分,即更新right = mid - 1
    • 如果目标值不在左半部分,那么我们将搜索范围缩小到右半部分,即更新left = mid + 1
    • 同理,如果右半部分是有序的,且目标值targetnums[mid]nums[right]之间(即nums[mid] < target <= nums[right]),则搜索范围缩小到右半部分。
    • 否则,目标值在左半部分,因此更新right = mid - 1
  4. 返回结果

    • 如果找到目标值,则返回它的索引。
    • 如果循环结束后仍未找到目标值,则返回-1

Java 代码的逐行解释

class Solution {public int search(int[] nums, int target) {int left = 0;int right = nums.length - 1;while (left <= right) {int mid = left + (right - left) / 2;// 检查中间元素是否为目标值if (nums[mid] == target) {return mid;}// 判断左半部分是否有序if (nums[left] <= nums[mid]) {// 检查目标值是否在左半部分if (nums[left] <= target && target < nums[mid]) {right = mid - 1;} else {left = mid + 1;}}// 右半部分是有序的else {// 检查目标值是否在右半部分if (nums[mid] < target && target <= nums[right]) {left = mid + 1;} else {right = mid - 1;}}}// 未找到目标值,返回-1return -1;}
}

时间复杂度

由于每次循环都会将搜索区间缩小一半,所以时间复杂度为 (O(\log n)),符合题目要求的高效查找。

总结

这个算法巧妙地利用了数组的部分有序特性,结合二分查找,在旋转数组中高效地查找目标值。

为什么如果nums[left] > nums[mid],说明右半部分是有序的。

如果nums[left] > nums[mid],说明左半区间存在旋转断点,而旋转断点之后的子数组都是有序的,所以右半部分是有序的。

nums[left] > nums[mid]时,确实可以判断左半区间存在旋转断点,这意味着左半部分并不是完全有序的。而旋转断点之后的子数组会保持有序状态,因此我们可以推断出右半部分是有序的

这也是为什么在这种情况下,我们可以安全地在右半部分进行查找,前提是目标值target在右半部分的范围内。反之,如果目标值不在右半部分的范围内,那么就去左半部分继续搜索。

你的理解完全正确!这种判断旋转数组中有序部分的方法,是解决这类问题的关键。😊

为什么这一部分代码片段if (nums[mid] < target && target <= nums[right]),如果使用判断条件if (nums[mid] <= target && target < nums[right])会得到错误的答案?

这个问题的核心在于边界条件的不同处理导致的结果差异。让我们仔细分析一下这两个条件的区别,以及为什么会得到不同的答案。

代码片段解释

if (nums[mid] < target && target <= nums[right])

条件比较

  1. 原条件if (nums[mid] < target && target <= nums[right])
  2. 错误条件if (nums[mid] <= target && target < nums[right])

原条件的含义:if (nums[mid] < target && target <= nums[right])

这个条件的意思是:

  • nums[mid] < target:目标值 target 要比 nums[mid] 大。
  • target <= nums[right]:目标值 target 小于或等于 nums[right]

该条件涵盖了目标值在右半部分有序区间内的情况,包括target等于nums[right]的情况。例如,如果右半部分的元素是[1, 2, 3, 4, 5],而target = 5,这个条件会成功匹配到5

错误条件的含义:if (nums[mid] <= target && target < nums[right])

这个条件的意思是:

  • nums[mid] <= target:目标值 target 可以等于 nums[mid]
  • target < nums[right]:目标值 target 必须严格小于 nums[right]

这个条件的一个问题是,当目标值等于nums[right]时,不会满足条件,即使target在右半部分有序区间内。例如,如果右半部分的元素是[1, 2, 3, 4, 5],而target = 5,因为5并不小于nums[right] = 5,这个条件将无法匹配到5

为什么使用错误条件会得到错误答案?

在旋转排序数组中,我们必须精确判断目标值是否在有序区间内。如果使用错误条件 if (nums[mid] <= target && target < nums[right]),就会漏掉当目标值等于右边界元素的情况,导致无法找到目标值,返回错误的结果(如返回-1)。

举个例子帮助理解

假设数组是[4, 5, 6, 7, 0, 1, 2]target = 2,那么:

  • nums[mid] 可能是0nums[right]2
  • 按照原条件 if (nums[mid] < target && target <= nums[right])
    • 0 < 2为真,2 <= 2也为真,条件成立,因此可以在右半部分继续查找。
  • 按照错误条件 if (nums[mid] <= target && target < nums[right])
    • 0 <= 2为真,但是2 < 2为假,因此条件不成立,会错误地调整查找区间。

总结

原条件 if (nums[mid] < target && target <= nums[right]) 保证了目标值即使等于右边界元素 nums[right] 时,仍然可以正确查找到。而错误条件 if (nums[mid] <= target && target < nums[right]) 会遗漏目标值等于右边界的情况,从而导致错误答案。

http://www.lryc.cn/news/471767.html

相关文章:

  • Spring Task—定时任务
  • Spring Boot 应用开发概述
  • Chrome谷歌浏览器加载ActiveX控件之allWebDesktop控件介绍
  • GitHub Star 数量前 5 的开源应用程序生成器
  • DBC文件当中新建CANFD等类型的报文
  • 基于SpringBoot的房地产销售管理系统【附源码】
  • 圆点虚线 Android
  • 贵州鑫宏远农业-始终致力于推动现代农业的科技创新与发展
  • 程序员做销售,从代码到客户的逆袭之路
  • Flink CDC系列之:理解学习Kubernetes模式
  • git合并相关操作详解
  • 前端经典【面试题】持续更新HTML、CSS、JS、VUE、FLUTTER、性能优化等
  • 【Linux知识】linux磁盘管理深入了解
  • Qt Essential Classes
  • 小小猫棒onu替换家用光猫,薅运营商带宽羊毛,突破1000M
  • 软件测试学习笔记丨Selenium学习笔记:css定位
  • python数据处理常用操作
  • 解决minio跨域问题
  • python 跳过当前循环
  • 数据库数据恢复—Oracle ASM磁盘组掉线 ,ASM实例无法挂载的数据恢复案例
  • jupyter notebook改变默认启动路径
  • libevent源码剖析-基本数据结构
  • 往期文章汇总——射频测量+无线通信+软件无线电+6G科普
  • 微信小程序 - 深 / 浅拷贝实现方法,微信小程序深拷贝与浅拷贝,函数方法封装直接调用使用,深拷贝cloneDeep和浅拷贝clone(深复制和浅复制)
  • Log4Net配置详解及输出自定义消息类示例代码
  • C++在实际项目中的应用第二节:C++与区块链
  • 浅记React面试丢人时刻
  • Python入门:学会Python装饰器让你的代码如虎添翼!(Python如何不改动原有函数代码添加一些额外的功能)
  • 【C++】哈希冲突的解决办法:闭散列 与 开散列
  • 复刻系列-原神 5.1 版本先行展示页