二分查找【数组】

news2024/7/4 6:03:12

⭐前言⭐

※※※大家好!我是同学〖森〗,一名计算机爱好者,今天让我们进入复习模式。若有错误,请多多指教。更多有趣的代码请移步Gitee
👍 点赞 ⭐ 收藏 📝留言 都是我创作的最大的动力!

题目

704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。


示例1:

1| 	输入: nums = [-1,0,3,5,9,12], target = 9
2| 	输出: 4
3| 	解释: 9在数组 nums 中,并且下标位置为 4

示例2:

	输入: nums = [-1,0,3,5,9,12], target = 2     
	输出: -1        
	解释: 2 不存在 nums 中因此返回 -1    

提示:

  • 你可以假设 nums 中的所有元素是不重复的。
  • n 将在 [1, 10000]之间。
  • nums 的每个元素都将在 [-9999, 9999]之间。

思路

题目分析:

  1. 从数组中查询元素,存在返回下标,不存在返回-1;
  2. 所有元素都是不重复的,不重复的升序数组
    注: 如果是有重复元素的数组,使用二分查找返回的下表可能不唯一;
  3. n的范围 [1, 10000] 和 nums[ i ] 的范围 [ -9999, 9999] 可以用 int 类型;

二分查找的思想

  • 确定区间 left,right
  • 用中间的元素与目标值 target 比较;
  • 如果中间元素大于target的值,由于数组升序,中间元素向右的元素都大于 target,全部排除;
  • 如果中间元素小于target的值,由于数组升序,中间元素向左的元素都小于 target,全部排除;
  • 中间元素等于target, 返回中间元素的下标;

易错点

  • 不确定区间的范围,[left,right] 和 [left,right)对于判断是 while( left < right) 和 while( left <=right)、right = mid 还是 right = mid + 1 至关重要;

接下来分别实现左闭右闭 [left, right] 和 左闭右开 [ left, right) 两种 区间分别求解

解法一 左闭右开

查询区间 [left, right)
控制条件

  • 循环条件:while (left < right)
    注: 这里是 小于,而不是 小于等于 因为 left == right 时 查询区间内没有元素了;
  • if(nums[mid] > target) right = mid; 因为nums[mid] > target , mid下标后面的元素都大于target,全部排除,因为区间是左闭右开,所以right = mid; 正好取不到mid; 如果不小心赋值成right = mid - 1,就漏掉了一个元素
  • if(nums[mid] < target) left = mid + 1; 因为 查询区间左边可以取到,mid 检查过了,从mid + 1开始遍历 所以 left = mid + 1;

例:在数组:-1,0,3,5,9,12 中查询 元素 0

第一步:初始化 left 和 right

left = 0;
right = nums.length;
// 循环条件
while(left < right){
	
}

查询区间是[left, right) 第一步初始化如下
初始化数组


第二步:计算mid的值

left = 0;
right = nums.length;
// 循环条件
while(left < right){
	// 防止溢出, 等同于(left + right) / 2
	int mid = left + (right - left) / 2;
}

第一次计算mid
计算mid


第三步:比较nums[mid] 和 target

left = 0;
right = nums.length;
// 循环条件
while(left < right){
	// 防止溢出, 等同于(left + right) / 2
	int mid = left + (right - left) / 2;
	if(nums[mid] > target) {
		// target 在左区间[left mid)
		right = mid;
	} else if (nums[mid] < target) {
		// target 在右区间[mid + 1, right)
		left = mid + 1;
	} else { // nums[mid] == target
		return mid; // 在数组中找到target, 直接返回下标
	}
}
return -1; // 没有找目标值

比较nums[mid] 和 target的大小, nums[mid] = 5 > target = 0 right = mid
第一次比较

left < right ; 0 < 3 进入循环

  • mid = left + (right - left) / 2 = 1

第二次计算mid
第二次计算mid
比较nums[mid] 和 target的大小, nums[mid] = 0 等于 target = 0
成功找到 target 返回 1;


完整代码

class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length;
        // 循环条件
        while(left < right){
            // 防止溢出, 等同于(left + right) / 2
            int mid = left + (right - left) / 2;
            if(nums[mid] > target) {
                // target 在左区间[left mid)
                right = mid;
            } else if (nums[mid] < target) {
                // target 在右区间[mid + 1, right)
                left = mid + 1;
            } else { // nums[mid] == target
                return mid; // 在数组中找到target, 直接返回下标
            }
        }
        return -1; // 没有找目标值
    }
}

运行结果:
在这里插入图片描述


错误演示

正确代码:while(left < right)
错误代码:while(left <= right)
例:在数组:-1,0,3,5,9,12 中查询 元素 7
完整代码

class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length;
        // 循环条件
        while(left <= right){ 
            // 防止溢出, 等同于(left + right) / 2
            int mid = left + (right - left) / 2;
            if(nums[mid] > target) {
                // target 在左区间[left mid)
                right = mid;
            } else if (nums[mid] < target) {
                // target 在右区间[mid + 1, right)
                left = mid + 1;
            } else { // nums[mid] == target
                return mid; // 在数组中找到target, 直接返回下标
            }
        }
        return -1; // 没有找目标值
    }
}

初始化:left = 0; right = arr.length;

在这里插入图片描述


mid = left + (right - left) / 2; mid = 3

在这里插入图片描述

比较nums[mid] 和 target 大小 5 < 7 left = mid + 1 = 4;

在这里插入图片描述


left <= right 4 < 6进入循环 mid = mid = left + (right - left) / 2; mid = 5

在这里插入图片描述


比较nums[mid] 和 target 大小 12 > 7 right = mid = 5

在这里插入图片描述


left <= right 4 < 5 进入循环 mid = left + (right - left) / 2; mid = 4

在这里插入图片描述

比较nums[mid] 和 target 大小 9 > 7 right = mid = 4

在这里插入图片描述

left <= right 4 = 4 进入循环, mid = left + (right - left) / 2; mid = 4;
比较nums[mid] 和 target 大小 9 > 7 right = mid = 4 程序进入了死循环;


解法二 左闭右闭

查询区间 [left, right]
控制条件

  • 循环条件:while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
  • if(nums[mid] > target) right = mid - 1; 因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
  • if(nums[mid] < target) left = mid + 1;

例:在数组:-1,0,3,5,9,12 中查询 元素 0

第一步初始化 left 和 right

left = 0;
right = nums.length - 1;
// 循环条件
while( left <= right) {

}

left right 初始化

在这里插入图片描述


第二步: 计算mid值

left = 0;
right = nums.length - 1;
// 循环条件
while( left <= right) {
	int mid = left + (right - left) / 2;
}

mid = left + (right - left) / 2; mid = 0 + (5 - 0) / 2 = 2

在这里插入图片描述


第三步:比较nums[mid] 和target

left = 0;
right = nums.length;
// 循环条件
while(left <= right){
	// 防止溢出, 等同于(left + right) / 2
	int mid = left + (right - left) / 2;
	if(nums[mid] > target) {
		// target 在左区间[left mid - 1]
		right = mid - 1;
	} else if (nums[mid] < target) {
		// target 在右区间[mid + 1, right]
		left = mid + 1;
	} else { // nums[mid] == target
		return mid; // 在数组中找到target, 直接返回下标
	}
}
return -1; // 没有找目标值

nums[ mid ] = 3 > target = 0 ; right = mid - 1 = 1

在这里插入图片描述


left = 0 , right = 1; 0 <= 1 进入循环; mid = left + (right - left) / 2; mid = 0;

在这里插入图片描述


nums[ mid ] = -1 < target = 0 ; left = mid + 1 = 1

在这里插入图片描述


left = 1 , right = 1; 1 <= 1 进入循环; mid = left + (right - left) / 2; mid = 1;

在这里插入图片描述

nums[ mid ] = 0 等于 target = 0; 成功查询到target 返回 1;

完整代码

class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        // 循环条件
        while(left <= right){
            // 防止溢出, 等同于(left + right) / 2
            int mid = left + (right - left) / 2;
            if(nums[mid] > target) {
                // target 在左区间[left mid - 1]
                right = mid - 1;
            } else if (nums[mid] < target) {
                // target 在右区间[mid + 1, right]
                left = mid + 1;
            } else { // nums[mid] == target
                return mid; // 在数组中找到target, 直接返回下标
            }
        }
        return -1; // 没有找目标值
    }
}

运行结果:
在这里插入图片描述

总结

二分查找的前提

  • 数组为有序序列
  • 数组中没有重复元素
  • 只能查找一个元素

二分查找易错点

  • 循环条件:
    前闭后开 [left, right) 循环条件为 left < right ;
    前闭后闭 [left , right] 循环条件为 left <= right;
  • 区间赋值问题:
    left = mid + 1;
    前闭后开 [left, right) right = mid ;
    前闭后闭 [left , right] right = mid - 1;

在这里插入图片描述


本文查考信息
代码随想录
【二分查找】详细图解
作图网站
力扣

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

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

相关文章

接口测试用例设计思路

&#xff08;我的公众号“墨石测试攻略”&#xff0c;关注获取软件测试相关知识及整套接口测试实战项目&#xff01;&#xff09; 接口测试用例的设计&#xff0c;从功能测试角度来说&#xff1a;首先需要分析接口文档。 现在很多公司都使用swagger来管理接口。swagger中可以…

fMRI时间序列振幅和相位对功能连接分析的影响

导读 目的&#xff1a;fMRI领域的一些研究使用瞬时相位(IP)表征(源自BOLD时间序列的解析表征)考察了脑区之间的同步性。本研究假设来自不同脑区的瞬时振幅(IA)表征可以为脑功能网络提供额外的信息。为此&#xff0c;本研究探索了静息态BOLD fMRI信号的这种表征&#xff0c;用于…

SpringBoot AnnotationFormatterFactory接口+自定义注解实现类型转换

参考资料 自定义AnnotationFormatterFactory实现注解方式类型转换Spring MVC 基于AnnotationFormatterFactory接口实现自定义的规则 目录 一. 前期准备1.1. 自定义转换标记注解1.2 入参form 二. 实现AnnotationFormatterFactory接口&#xff0c;构建格式化Factory2.1 code补全…

【7】一篇文章学习 Linux 中一些硬核的常用知识

目录 一、systemctl二、软链接三、日期&#xff08;date 命令&#xff09;四、Linux 的时区(1) 修改时区(2) ntp 五、IP 地址六、主机名七、域名解析八、配置 Linux 的固定 IP 地址(1) 在 VMwareWorkstation 中配置 IP 地址网关和网段&#xff08;IP 地址的范围&#xff09;(2)…

[陇剑杯 2021]之Misc篇(NSSCTF)刷题记录④

NSSCTF-Misc篇-[陇剑杯 2021] jwt&#xff1a;[陇剑杯 2021]jwt&#xff08;问1&#xff09;[陇剑杯 2021]jwt&#xff08;问2&#xff09;[陇剑杯 2021]jwt&#xff08;问3&#xff09;[陇剑杯 2021]jwt&#xff08;问4&#xff09;[陇剑杯 2021]jwt&#xff08;问5&#xff0…

洗地性价比高的是哪款?性价比高的洗地机推荐

在如今人工智能随处可见的时代&#xff0c;洗地机已经成为了我们家庭清洁的得力助手&#xff0c;它用高效便捷的清洁方式&#xff0c;对于地面的灰尘或者地板之间的缝隙里的细小垃圾&#xff0c;能够快速清理&#xff0c;省时省力。然而&#xff0c;对于很多消费者来说&#xf…

一文带你学会如何写一份糟糕透顶的简历

我们每个人几乎都会面对找工作这件事&#xff0c;而找工作或者说求职首先就是要写一份简历。今天狗哥将以一个不同的视角带你写一份无与伦比&#xff0c;糟糕透顶的求职简历&#xff0c;说实话&#xff0c;其实几年前&#xff0c;我就是这么写的。 目录 1. 文件名 2. 基本信…

AttributeError: ‘ChatGLMModel‘ object has no attribute ‘prefix_encoder‘

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

基于蛋白-配体复合物药效团药物设计(Pharmacophore)

基于蛋白-配体复合物药效团药物设计&#xff08;Pharmacophore&#xff09; step 1.蛋白-配体复合物准备 点击File-->Import Structures导入之前已经下载好的1IEP.pdb&#xff08;Abl蛋白和Imatinib的晶体复合物&#xff09; 蛋白准备&#xff1a;点击Tasks--->Protei…

18、越狱

一、越狱 1.1 越狱 通过iOS系统安全启动链漏洞,从而禁止掉信任链中负责验证的组件.拿到iOS系统最大权限Root权限 1.2 iOS系统安全启动链 当启动一台iOS设备时,系统首先会从只读的ROM中读取初始化指令,也就是系统的引导程序(事实上所有的操作系统启动时都要经过这一步,只是过程…

Pytorch深度学习笔记(十一)卷积神经网络CNN

目录 1.概述 2.单通道卷积 3.多通道卷积 4.卷积层常见的参数 5.代码实现&#xff08;卷积神经网络训练MNIST数据集&#xff09; 推荐课程&#xff1a;10.卷积神经网络&#xff08;基础篇&#xff09;_哔哩哔哩_bilibili 1.概述 全连接神经网络&#xff1a;完全由线性层串…

最佳实践|如何写出简单高效的 Flink SQL?

摘要&#xff1a;本文整理自阿里巴巴高级技术专家、Apache Flink PMC 贺小令&#xff0c;在 Flink Forward Asia 2022 生产实践专场的分享。本篇内容主要分为三个部分&#xff1a; 1. Flink SQL Insight 2. Best Practices 3. Future Works Tips&#xff1a;点击「阅读原文」查…

android之 Launcher改造仿桌面排版的效果

一&#xff0c;背景 1.1 新接手一个灯光控制项目&#xff0c;其页面和效果还是比交复杂的&#xff0c;其中一个功能就是仿苹果桌面来排版灯具&#xff0c;支持拖拽&#xff0c;分组&#xff0c;分页。 拖动图标的时候判断是否空白位置还是已经有占位了&#xff0c;有的话就把…

pikachu靶场-RCE

RCE漏洞概述 可以让攻击者直接向后台服务器远程注入操作系统命令或者代码&#xff0c;从而控制后台系统。 远程系统命令执行 命令执行漏洞&#xff08;Command Execution&#xff09;即黑客可以直接在Web应用中执行系统命令&#xff0c;从而获取敏感信息或者拿下shell权限 更…

Linux离线状态下安装cuda、cudnn、cudatoolkit

目录 1. 下载与安装说明2. CUDA安装3. cuDNN安装4. cudatoolkit安装5. 测试安装成功 1. 下载与安装说明 工具包下载地址 CUDA历史版本下载地址&#xff1a;https://developer.nvidia.com/cuda-toolkit-archivecuDNN历史版本下载地址&#xff1a;https://developer.nvidia.com/r…

logback日志框架集成方式

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、logback是什么&#xff1f;二、使用步骤1.使用方式控制台输出配置文件输出配置html输出配置定期删除配置方式 总结 前言 提示&#xff1a;这里可以添加本文…

C++每日一练:最长递增区间 阿波罗的魔力宝石 投篮

文章目录 前言一、最长递增区间二、阿波罗的魔力宝石三、投篮总结 前言 今天的题太简单&#xff0c;甚至 “最长递增区间” 和 “投篮” 就是一个问题。实在没事干&#xff0c;也给做了&#xff01;直接上代码算了… 提示&#xff1a;以下是本篇文章正文内容 一、最长递增区间…

LSSANet:一种用于肺结节检测的长、短切片感知网络

文章目录 LSSANet: A Long Short Slice-Aware Network for Pulmonary Nodule Detection摘要方法Long Short Slice GroupingLong Short Slice-Aware Network 实验结果 LSSANet: A Long Short Slice-Aware Network for Pulmonary Nodule Detection 摘要 提出了一个长短片感知网…

【JAVA程序设计】(C00130)基于SpringBoot的社区养老医疗综合服务系统

基于SpringBoot的社区养老医疗综合服务系统 项目简介项目获取开发环境项目技术运行截图 项目简介 基于基于SpringBoot的社区养老医疗综合服务系统共分为三个角色&#xff1a;系统管理员、医生、用户 管理员角色包含以下功能&#xff1a; 用户管理、角色管理、部门管理、字典管…

【Java EE】-JavaScript详解

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀冬瓜的主页&#x1f319; 专栏&#xff1a;【JavaEE】 分享: 且视他人如盏盏鬼火&#xff0c;大胆地去走你的道路。——史铁生《病隙碎笔》 主要内容&#xff1a;HTML中引入JS的三种方式。JS语法分析&#xff0c;JS是动态弱…