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

【算法小课堂】二分查找算法

在这里插入图片描述

简单思路:

当我们要从一个序列中查找一个元素的时候,最快想到的方法就是顺序查找法(即:从前到后依次查找)。但这种方法过于无脑,就是暴力的把每个元素都排查一遍。元素个数少的时候还行,一旦元素个数多起来,效率是非常低下,所以在实际中这种查找的方法是被摒弃的。

当题目或者实际对时间复杂度有着很高的要求的时候,这种暴力解法就显得很乏力

这里就不得不介绍一种简单且效率较高的查找方法了:二分查找法,又称折半查找法。但该方法是建立在有序的前提下的,基本思路就是:

利用两个指针left和right,不断取中点来不断把区间减小从而找到我们的答案

二分查找法的优势:

  • 二分查找法的时间复杂度:O(logN)

  • 暴力解法的时间复杂度:O(N)

如何直观来体现二分查找法时间复杂度的优势呢?

img

可以看出 二分查找 在查找数字 37 时只需3次,而 顺序查找 在查找37时需要12次。

二分查找的条件:

很多算法书都是写的具有有序性,其实更准确的是具有二段性

  • 也就是具有可以把数组分为两端的性质

二分查找有两个限制条件:

  1. 查找的数量只能是一个,不能是多个
  2. 查找的对象在逻辑上必须是有序的(这个不是必要条件,更深层次是就有二段性)

朴素二分查找:

1.left=0,right=数组最后一个位置的下标

2.取中点:mid=(right-left)/2

二分法的思想很简单,因为整个数组是有序的,数组默认是递增的。

首先选择数组中间的数字和需要查找的目标值比较

  • 如果相等最好,就可以直接返回答案了

  • 如果不相等

    如果中间的数字大于目标值,则中间数字向右的所有数字都大于目标值,全部排除

    如果中间的数字小于目标值,则中间数字向左的所有数字都小于目标值,全部排除

704. 二分查找

以此题为例:

class Solution {
public:int search(vector<int>& nums, int target) {int left=0;int right=nums.size()-1;while(left<=right){int mid=left+(right-left)/2;if(nums[mid]==target) return mid;if(nums[mid]>target) right=mid-1;if(nums[mid]<target) left=mid+1;}return -1;}
};

朴素二分查找的模版:

        while(left<=right){int mid=left+(right-left)/2;if(nums[mid]==target) return mid;if(nums[mid]>target) ...;if(nums[mid]<target) ...;}return ...;

二分查找左右端点:

我们通过一个例子:

34. 在排序数组中查找元素的第一个和最后一个位置

本题我们利用二分来解决左右端点的问题,首先left和right肯定有的

我们通过一个示例来了解本题:[1,2,3,3,3,4,5]

查找左端点:我们这里用t来代替target(这样比较好叙述)

img

  • 二分的思路操作:我们可以将上述示例分为两个部分,因为我们现在查找左端点,因此我可以将示例分为【[1,2],[3,3,3,4,5]】

img

  1. 当x<t时,处于【1,2】这个区间,left=mid+1
  2. 当x>=t时,处于【3,3,3,4,5】这个区间,right=mid(这里不能等于mid-1,因为如果mid=0,right=-1会越界)
  • 细节处理:

循环条件:

  1. left<right
  2. left<=right ×

我们选择那种呢?我们来讨论一下:

img

  1. 有结果
  2. 全大于t(t1),right一直向左走,最后right为left结束,如果是left<=right会死循环
  3. 全小于t(t2),left一直向右走,最后left在right右边结束

以此我们只能选择第一种不能选择第二种!

求中间的操作:

  1. left+(right-left)/2 ×
  2. left+(right-left+1)/2

我们考虑一下极端情况就可以知道了!当只剩下两个元素的时候:

img
第一种没有问题,第二种mid=0+2/2=1,当进行left+1操作的时候会发生越界

查找右端点

  • 二分的思路操作:我们可以将上述示例分为两个部分,因为我们现在查找左端点,因此我可以将示例分为【[1,2,3,3,3].[4,5]】

img

  1. 当x<=t时,处于【1,2,3,3,3】这个区间,left=mid
  2. 当x>t时,处于【4,5】这个区间,right=mid-1
  • 细节处理:

循环条件:

  1. left<right
  2. left<=right ×

还是选择left<right

求中间的操作:

  1. left+(right-left)/2
  2. left+(right-left+1)/2 ×

我们考虑一下极端情况就可以知道了!当只剩下两个元素的时候:

img

第一种当mid=0+1/2=0时,right=mid-1越界,第二种没有问题

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {//特殊情况处理一下if(nums.size()==0)return {-1,-1};int left=0,right=nums.size()-1;vector<int> ret;//查找左端点while(left<right){int mid=left+(right-left)/2;if(nums[mid]<target)left=mid+1;if(nums[mid]>=target)right=mid;}//当left==right时就是结果if(nums[left]!=target)return {-1,-1};else ret.push_back(left);//查找右端点left=0,right=nums.size()-1;while(left<right){int mid=left+(right-left+1)/2;if(nums[mid]<=target)left=mid;if(nums[mid]>target)right=mid-1;}if(nums[right]!=target)return {-1,-1};else ret.push_back(right);return ret;}
};

查找区间左右端点的模版:

image-20231001143903966

模版,这里主要是取中间这里不太一样,左端点时不用+1,右端点+1(记忆当下面出现-1,上面就+1)

至于left和right可以现场推导

在这里插入图片描述

相关文章:

【算法小课堂】二分查找算法

简单思路&#xff1a; 当我们要从一个序列中查找一个元素的时候&#xff0c;最快想到的方法就是顺序查找法&#xff08;即&#xff1a;从前到后依次查找&#xff09;。但这种方法过于无脑&#xff0c;就是暴力的把每个元素都排查一遍。元素个数少的时候还行&#xff0c;一旦元…...

git修改提交历史中的author信息

全局设置 git config --global user.name "作者名" 局部设置(本项目) git config user.name "作者名" git修改提交作者和邮箱-CSDN博客 git修改提交作者和邮箱-CSDN博客...

【gitlab】本地项目上传gitlab

需求描述 解决方法 下面的截图是gitlab空项目的描述 上传一个本地项目按其中“Push an existing folder”命令即可。 以renren-fast项目为例 # 用git bash 下载renren-fast项目 git clone https://gitee.com/renrenio/renren-fast.git# 在renren-fast的所属目录 打开git ba…...

freertos信号量之计数信号量

freertos信号量之计数信号量 简介例程 简介 计数信号量&#xff08;Counting Semaphore&#xff09;用于管理共享资源的访问。以下是计数信号量的常用函数及其说明&#xff1a; 1&#xff09;xSemaphoreCreateCounting(unsignedportBASE_TYPE uxMaxCount, unsignedportBASE_T…...

wc命令使用指南 | 教你如何高效统计文件字数、行数和字符数

文章目录 wc命令使用指南1. 引言1.1 什么是wc命令&#xff1f;1.2 wc命令的作用和用途1.3 wc命令的常用参数 2. 基本使用2.1 安装和启动wc命令2.2 统计文件的行数2.3 统计文件的字数2.4 统计文件的字符数2.5 统计文件的词数2.6 统计文件的最长行长度 3. 高级使用3.1 统计多个文…...

网络安全:发起一次CSRF攻击!

一、如何发起一次CSRF攻击 原理&#xff1a;CSRF 的本质实际上是利用了 Cookie 会自动在请求中携带的特性&#xff0c;通过伪造请求来执行恶意操作。 1、目标网站信息&#xff1a; 接口地址&#xff1a;https://victim.com/change-password 请求类型&#xff1a;get/post 接…...

java上传文件到指定服务器

首先要知道服务器的用户名和密码。 注意&#xff1a;一般情况&#xff0c;如果不是强制要求&#xff0c;尽量不要将文件上传到服务器 步骤&#xff1a; 1.导入依赖 <!--图片上传到服务器需要的依赖--> <dependency> <groupId>com.jcr…...

揭秘 Go 中的 new() 和 make() 函数

Go&#xff08;或 Golang&#xff09;是一种现代、静态类型、编译型的编程语言&#xff0c;专为构建可扩展、并发和高效的软件而设计。它提供了各种内置的函数和特性&#xff0c;帮助开发人员编写简洁高效的代码。其中包括 new() 和 make() 函数&#xff0c;这两个函数乍看起来…...

【Spring Cloud】深入探索统一网关 Gateway 的搭建,断言工厂,过滤器工厂,全局过滤器以及跨域问题

文章目录 前言为什么需要网关以及网关的作用网关的技术实现 一、Gateway 网关的搭建1.1 创建 Gateway 模块1.2 引入依赖1.3 配置网关1.4 验证网关是否搭建成功1.5 微服务结构分析 二、Gateway 断言工厂2.1 Spring 提供的断言工厂2.2 示例&#xff1a;设置断言工厂 三、Gateway …...

计算机竞赛 题目:基于卷积神经网络的手写字符识别 - 深度学习

文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…...

关于flink重新提交任务,重复消费kafka的坑

异常现象1 按照以下方式设置backend目录和checkpoint目录&#xff0c;fsbackend目录有数据&#xff0c;checkpoint目录没数据 env.getCheckpointConfig().setCheckpointStorage(PropUtils.getValueStr(Constant.ENV_FLINK_CHECKPOINT_PATH)); env.setStateBackend(new FsStat…...

Win11右键恢复Win10老版本

Win11右键恢复Win10老版本 最近自己更新了windows11的OS,整体感觉都是不错的,但是就是每次右键菜单我都要再次点击下展开更多选项,这对追求极简主义的我,就是不爽, 手动恢复win10操作吧! 第一种:创建文件(简单快速) 1.新建一个resoreRightKey.reg文件,并在里面填入如下代码 W…...

ur机械臂30003端口socket通信踩坑(double类型数据怎么解析)

坑的由来 都知道在网络通信时要把网络字节序转化为主机字节序才行&#xff0c;但是c里的标准库函数ntohl默认是转换32位字节序的数据&#xff0c;也就是说默认是转换float类型的数据&#xff1b;而ur机械臂30003端口发送的是double类型的数据&#xff0c;没法直接用ntohl进行转…...

代理IP与Socks5代理的技术奇妙之旅

随着数字化时代的崛起&#xff0c;网络工程师们日益承担着维护网络稳定性和保护数据安全的重任。在这个充满挑战的世界里&#xff0c;代理IP与Socks5代理技术成为了他们的秘密武器&#xff0c;本文将带您踏上一段技术奇妙之旅&#xff0c;深入了解这两项技术在不同领域中的应用…...

自动化测试定位不到元素?可能是 frame 在搞鬼

很多人在用Splinter或Selenium定位页面元素的时候会遇到定位不到的问题&#xff0c;明明元素就在那儿&#xff0c;就是定位不到&#xff0c;这种情况很有可能是frame在搞鬼。 说白了就是网站上的网页A&#xff0c;又嵌入了其他网页B。你访问了网页A&#xff0c;在里面可以看到…...

uni-app 开发中,监听 input 键盘事件获取不到按下按键值怎么办?

uniapp 开发 H5 时&#xff0c;无法监听按钮键盘事件的原因以及解决方法。 问题描述&#xff1a; 不少 uni-app 开发者在使用 input 组件时&#xff0c;监听 keyup 事件时&#xff0c;获取不到键盘的 keyCode。编写的代码如下&#xff1a; <template><input keyup&…...

【juc】countdownlatch实现并发网络请求

目录 一、截图示例二、代码示例2.1 测试代码2.2 接口代码 一、截图示例 二、代码示例 2.1 测试代码 package com.learning.countdownlatch;import lombok.extern.slf4j.Slf4j; import org.springframework.web.client.RestTemplate;import java.util.Arrays; import java.uti…...

在供应链管理中,如何做好库存分析?库存分析有哪些监控指标?

在供应链管理中&#xff0c;库存分析是其重要的一环。库存分析的方法繁杂且广泛&#xff0c;选择正确的方法才能更好的进行库存分析&#xff0c;下面就为大家盘点一些常用的库存分析方法和监控指标&#xff0c;全程干货&#xff0c;建议收藏&#xff01; 01 如何进行库存分析&…...

黑豹程序员-架构师学习路线图-百科:Database数据库

文章目录 1、什么是Database2、发展历史3、数据库排行网4、总结 1、什么是Database 当今世界是一个充满着数据的互联网世界&#xff0c;各处都充斥着大量的数据。即这个互联网世界就是数据世界。 支撑这个数据世界的基石就是数据库&#xff0c;数据库也可以称为数据的仓库。 …...

你相信光吗?黑灯工厂重新相信“光”

你知道“黑灯工厂”吗&#xff1f;望文生义&#xff0c;所谓黑灯工厂&#xff0c;就是可以不需要照明的工厂。全程流水线自动化生产&#xff0c;无人干预、无人值守&#xff0c;工厂变成黑匣子&#xff0c;原材料进去&#xff0c;成品出来&#xff0c;流水线上百分百自动化。 完…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...