【leetcode】 数组二分查找

2023-09-22 01:39:15

【leetcode】 数组二分查找

1.二分查找

二分查找(Binary Search),也称为折半查找,是一种在有序数组中查找特定元素的高效算法。它的基本思想是不断将待查找区间缩小一半,直到找到目标元素或确定目标元素不在数组中为止。这种查找方法比线性查找效率高,因为它可以快速排除掉大部分不可能包含目标元素的区间,从而减少了比较次数。

二分查找的工作原理如下:

  1. 首先,确定查找范围的左边界 left 和右边界 right,通常初始时 left 设为数组的起始索引,right 设为数组的结束索引。

  2. 计算中间元素的索引 mid,可以使用 (left + right) // 2 计算。

  3. 比较中间元素与目标元素的大小:

    • 如果中间元素等于目标元素,查找成功,返回 mid
    • 如果中间元素大于目标元素,说明目标元素可能在左半边,将 right 更新为 mid - 1,然后重复步骤2。
    • 如果中间元素小于目标元素,说明目标元素可能在右半边,将 left 更新为 mid + 1,然后重复步骤2。
  4. 重复步骤2和步骤3,直到 left 大于 right,此时说明查找范围为空,目标元素不在数组中,可以返回-1或其他指定的标志来表示查找失败。

二分查找的时间复杂度是 O(log n),其中 n 是数组的长度。由于每次查找都将查找范围缩小一半,因此它在大型有序数组中表现出色,是一种高效的查找算法。但要使用二分查找,前提是数组必须是有序的,否则无法保证正确的查找结果。

2.举个例子

当使用二分查找时,通常需要一个有序数组。以下是一个简单的例子,演示如何使用二分查找在有序数组中查找特定的目标元素。

假设有一个有序整数数组 nums 如下:

nums = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

现在,我们要查找数字 12 是否在这个数组中,并返回其索引位置。我们可以使用二分查找来实现:

  1. 初始化左边界 left 为 0,右边界 right 为数组的长度减一,即 left = 0right = 9
  2. 计算中间索引 midmid = (0 + 9) // 2 = 4
  3. 比较 nums[4](即数组的中间元素 10)与目标元素 12
    • 因为 10 < 12,所以目标元素可能在右半部分,更新 leftmid + 1,即 left = 5
  4. 重复步骤2和步骤3:
    • 计算中间索引 midmid = (5 + 9) // 2 = 7
    • 比较 nums[7](即数组的中间元素 16)与目标元素 12
      • 因为 16 > 12,所以目标元素可能在左半部分,更新 rightmid - 1,即 right = 6
  5. 重复步骤2和步骤3:
    • 计算中间索引 midmid = (5 + 6) // 2 = 5
    • 比较 nums[5](即数组的中间元素 12)与目标元素 12
      • 因为 12 == 12,查找成功,返回 mid = 5

最终,我们通过二分查找找到了目标元素 12,并返回它在数组中的索引位置为 5。这个例子演示了如何使用二分查找在有序数组中快速查找目标元素。这个算法在大型有序数组中的效率非常高,因为它可以快速排除掉一半的元素。

以下是使用Python实现的二分查找算法的示例代码:

def binary_search(nums, target):
    left, right = 0, len(nums) - 1
    
    while left <= right:
        mid = (left + right) // 2
        
        if nums[mid] == target:
            return mid  # 找到目标元素,返回索引
        elif nums[mid] < target:
            left = mid + 1  # 目标元素在右半部分
        else:
            right = mid - 1  # 目标元素在左半部分
    
    return -1  # 目标元素不在数组中

# 示例用法
nums = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
target = 12
result = binary_search(nums, target)

if result != -1:
    print(f"目标元素 {target} 在数组中的索引位置是 {result}")
else:
    print(f"目标元素 {target} 不在数组中")

这段代码实现了一个名为 binary_search 的函数,该函数接受一个有序数组 nums 和要查找的目标元素 target 作为参数。它使用一个循环来在数组中执行二分查找,不断更新 leftright 边界,直到找到目标元素或确定它不在数组中。如果找到目标元素,函数返回目标元素的索引;否则,返回 -1 表示目标元素不在数组中。

在示例用法中,我们使用有序数组 nums 进行二分查找,查找目标元素 12,并输出结果。这个例子演示了如何使用二分查找函数来查找目标元素。

3.二分查找的进阶

在进行二分查找时,有一些进阶技巧和注意事项可以帮助你更好地处理边界情况、提高效率,以及适应不同的问题。以下是一些进阶方面的考虑:

  1. 边界判断:

    • 在进入二分查找循环之前,通常需要确保输入数据是有效的,例如,数组不为空。
    • 在更新边界 leftright 时,需要注意边界情况,确保不会越界。
  2. 中值选取:

    • 通常,中值 mid 的计算可以使用 (left + right) // 2,但如果 leftright 很大,相加可能会导致整数溢出。为了避免这种情况,可以使用 left + (right - left) // 2 来计算中值。
    • 如果使用编程语言支持的浮点数类型,也可以使用 left + (right - left) / 2.0 来计算中值。
  3. 查找变种:

    • 二分查找通常用于在有序数组中查找目标元素,但也可以通过变种来处理其他问题,如查找第一个出现的目标元素、最后一个出现的目标元素或第一个大于/小于目标元素的元素。
    • 这些变种可以通过稍微修改二分查找的条件来实现。
  4. 左闭右开区间:

    • 有时,为了避免边界问题,可以使用左闭右开区间来进行二分查找。即,定义 right 为数组长度,但在比较中不包括 nums[right]
    • 这可以简化边界处理,但需要在结果中进行相应的调整。
  5. 递归实现:

    • 除了迭代实现外,还可以使用递归来实现二分查找。递归实现通常更简洁,但可能会占用更多的内存空间。
  6. 特殊条件:

    • 在某些情况下,可以根据特殊条件提前终止二分查找,而不必等到完全找到目标元素。这可以提高效率,尤其是在大规模数据上。
  7. 性能优化:

    • 对于非常大的数据集,可能需要考虑性能优化。例如,可以使用二分查找的变种,如插值查找或斐波那契查找,以加速查找过程。

这些是在进行二分查找时的一些进阶技巧和注意事项。具体实现时,要根据问题的要求和数据特点来选择合适的策略和边界条件。

4.leetcode原题

当涉及到进阶的二分查找问题时,LeetCode上有许多具有一定难度的原题。以下是一些比较复杂的LeetCode二分查找问题的示例:

  1. 搜索旋转排序数组 II (Search in Rotated Sorted Array II)

    • 问题描述:给定一个包含重复元素的升序排序数组,判断某个目标元素是否存在其中。
    • 难度:中等
    • 链接:https://leetcode.com/problems/search-in-rotated-sorted-array-ii/
  2. 寻找旋转排序数组中的最小值 II (Find Minimum in Rotated Sorted Array II)

    • 问题描述:给定一个包含重复元素的升序排序数组,查找数组中的最小元素。
    • 难度:困难
    • 链接:https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/
  3. 寻找峰值 II (Find Peak Element II)

    • 问题描述:给定一个二维矩阵,查找其中的峰值元素。一个峰值元素是指其值大于或等于相邻元素的值。
    • 难度:困难
    • 链接:https://leetcode.com/problems/find-peak-element-ii/
  4. 搜索二维矩阵 II (Search a 2D Matrix II)

    • 问题描述:给定一个二维矩阵,其中的每行和每列都按升序排列,编写一个函数来查找目标值是否存在其中。
    • 难度:中等
    • 链接:https://leetcode.com/problems/search-a-2d-matrix-ii/

这些问题都具有一定的难度,需要对二分查找算法有深入的理解和应用。解决它们需要灵活运用二分查找的思想,并考虑特殊情况和边界条件。如果你想挑战更复杂的二分查找问题,可以尝试解决上述LeetCode题目。

更多推荐

基于微信小程序的实验室预约管理系统设计与实现

前言💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗👇🏻精彩专栏推荐订阅👇🏻2023-2024年最值得选的微信小程序毕业设计选题大全:100个热门选

python/C++二分查找库函数(lower_bound() 、upper_bound,bisect_left,bisect_right)

二分查找是一种经典的搜索算法,广泛应用于有序数据集中。它允许在大型数据集中高效地查找目标元素,减少了搜索的时间复杂度。本文将介绍在C++和Python中内置的二分查找函数,让二分查找变得更加容易。c++lower_bound()、upper_bound定义在<algorithm>头文件中,lower_bound和upp

大数据分布式处理框架Hadoop

大数据是什么大数据容量常以TB、PB、甚至EB为单位,远超传统数据库的承载能力,无论入库还是查询都出现性能瓶颈。Hadoop是什么Hadoop是开源的分布式计算技术框架,用于处理大规模数据和实现分布式存储。Hadoop核心组件HDFS(HadoopDistributedFileSystem分布式文件系统):是Hadoo

学习Nano编辑器:入门指南、安装步骤、基本操作和高级功能

文章目录使用Nano编辑器入门指南引言1.1关于Nano编辑器1.2Nano的起源和特点安装Nano2.1在Debian/Ubuntu系统上安装Nano2.2在CentOS/RHEL系统上安装Nano2.3在其他Linux发行版上安装Nano启动Nano3.1命令行启动Nano3.2打开文件Nano的基本操作4.1光标

如何批量为文件夹命名

如果你想要命名一些这样名字具有规律性的文件夹,当文件的数量增多,一个一个命名是非常耗费时间的。很容易想到,如果使用EXCEL,只需往下拉,就能很轻松的拉出1到5。那么,我们如何利用EXCEL来对文件夹进行快速的批量命名呢?以上图为例子,人名可能是我们已知的,可以从表格直接复制过来。而客户名1到客户名5,我们可以直接使用

大数据Flink(六十四):Flink运行时架构介绍

文章目录Flink运行时架构介绍一、系统架构二、​​​​​​​​​​​​​​整体构成三、作业管理器(JobManager)四、任务管理器(TaskManager)Flink运行时架构介绍我们已经对Flink的主要特性和部署提交有了基本的了解,那它的内部又是怎样工作的,集群配置设置的一些参数又到底有什么含义呢?接下来我们

基于vue的黑马前端项目小兔鲜

目录项目学习初始化项目建立项目引入elementpluselementPlus主题设置配置axios路由引入静态资源自动导入scss变量Layout页组件结构快速搭建字体图标渲染一级导航渲染吸顶导航交互实现Pinia优化重复请求Home页分类实现banner轮播图新鲜好物实现人气推荐实现懒加载指令实现产品列表实现Goo

正确设置PyTorch训练时使用的GPU资源

背景:最近在使用HuggingFace的transformersapi来进行预训练大模型的微调,机器是8卡的GPU,当我调用trainer.train()之后,发现8个GPU都被使用了,因为这个机器上面还有其他人跑的模型,当我进行训练的时候,GPU的使用率就接近了100%,这样导致其他人的模型响应速度特别的慢,因为他们

微信小程序如何刷新当前页面

微信小程序是一种快速发展的移动应用程序开发平台,它提供了许多功能和特性,使开发者能够轻松创建功能丰富的小程序。在开发小程序时,有时我们需要刷新当前页面来更新数据或重新加载页面内容。本文将解释如何在微信小程序中刷新当前页面的代码。引言微信小程序的流行使得越来越多的开发者将其作为构建移动应用的首选平台。然而,与传统的网页开

快速了解Apipost

随着数字化转型的加速,API(应用程序接口)已经成为企业间沟通和数据交换的关键。而在API开发和管理过程中,API文档、调试、Mock和测试的协作显得尤为重要。Apipost正是这样一款一体化协作平台,旨在解决这些问题,提高API开发效率和质量。Apipost提供API文档管理功能,让后端开发人员可以在开发完接口调试的

cookie信息无法获取问题研究

背景在oneapi这个前后端都有的开源项目中,我想接入chatnextweb到oneapi的后端。由于需要二开chatnextweb,添加登录注册功能,考虑到java后端的性能问题和内存占用,决定不重启写个服务,而是将登录注册接入到oneapi的登录注册api,没错,和oneapi的前端公用一套登录注册熬了个大夜后,终

热文推荐