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

算法基础学习——二分查找(附带Java模板)

有单调性的数列一定可以使用二分,没有单调性的题目也可能可以使用二分;

(一)整数二分

二分的本质:

        在某个整数区间内,存在某种性质使得区间内左半边的数都不满足该性质;而右半边的数都满足该性质;那么二分的作用就是找到左右这两个分界点;

1.找满足红色性质的边界点(如图上)

如果是让l等于mid(即找左半边的分界点)则要记得mid = (l+r+1)/2

2.找满足绿色性质的边界点(如图上)

如果是让r等于mid(即找右半边的分界点)则mid = (l+r)/2,不用另外加1;

情况1为什么额外加1? 答:因为在程序中,(l+r)/2是向下取整;当遇到遇到r=l+1(l和r只相差1,数组只有两个元素)的情况,(l+r)/2就等于l,这时候mid=(l+r)/2就是mid=l如下图所示:这次循环相当于没有变化,再次循环也不会有变化,进入死循环;

基本思想:不断缩小答案区间,当区间长度为一时,就是答案;

时间复杂度:平均O(logn) 

步骤:
  1. 先写出基本模板:mid = (l+r)/2

  2. 定义判断条件check()函数

  3. 看应该是让l=mid还是r=mid;如果应该l=mid则把前面的mid改为 mid=(l+r+1)/2

模板:
// 检查x是否满足某种性质  
private static boolean check(int x) {  /* ... */  
}  // 区间[left, right]被划分成[left, mid]和[mid + 1, right]时使用: 
// 或者称之为左二分查询,查找左侧第一个满足条件的数
private static int leftBinarySearch(int[] arr, int left, int right) {  while (left < right) {  int mid = arr[left + right >> 1];  if (check(mid)) {  right = mid;    // check()判断mid是否满足性质  } else {  left = mid + 1;  }  }  return left;  
}  // 区间[left, right]被划分成[left, mid - 1]和[mid, right]时使用:  
// 或者称之为右二分查询,查找右侧最后一个满足条件的数
private static int rightBinarySearch(int[] arr, int left, int right) {  while (left < right) {  int mid = arr[left + right + 1 >> 1];  if (check(mid)) {  left = mid;    // check()判断mid是否满足性质  } else {  right = mid - 1;  // 有加必有减}  }  return left;  
}

(二)浮点数二分

典型问题:求一个数的平方根

基本思想:不断缩小答案区间,当区间长度足够小时(即左右边界之差足够小),边界的值就约等于答案;

时间复杂度:平均O(logn) 

步骤:
  • mid就等于(r+l)/2;

  • while循环判定条件为r-l>1e-8(左右边界之差足够小时结束循环)

模板:
// 检查x是否满足某种性质  
private static boolean check(int x) {  /* ... */  
}  // 区间[left, right]被划分成[left, mid]和[mid + 1, right]时使用: 
// 或者称之为左二分查询,查找左侧第一个满足条件的数
private static int leftBinarySearch(int[] arr, int left, int right) {  while (left < right) {  int mid = arr[left + right >> 1];  if (check(mid)) {  right = mid;    // check()判断mid是否满足性质  } else {  left = mid + 1;  }  }  return left;  
}  // 区间[left, right]被划分成[left, mid - 1]和[mid, right]时使用:  
// 或者称之为右二分查询,查找右侧最后一个满足条件的数
private static int rightBinarySearch(int[] arr, int left, int right) {  while (left < right) {  int mid = arr[left + right + 1 >> 1];  if (check(mid)) {  left = mid;    // check()判断mid是否满足性质  } else {  right = mid - 1;  // 有加必有减}  }  return left;  
}

注意点:

  1. 使用二分一定可以找到一个满足条件的边界点(不会出现无解的情况);

  2. 整数二分中,l和r表示的是区间左右边界的数组下标;当遍历结束后l=r,arr[r] 就是所找的边界点;

  3. 浮点数二分中,l和r表示的不是数组下标,而是左右边界本身;

时间复杂度分析

二分查找(Binary Search)的时间复杂度分析如下:

1. 最好情况(Best Case)

如果目标元素正好是数组的中间元素,那么只需一次比较就能找到,时间复杂度为:

O(1)O(1)

2. 最坏情况(Worst Case)

每次查找都会将搜索范围缩小一半,假设数组长度为 nn,那么最多需要查找的次数是:

T(n)=T(n/2)+O(1)T(n) = T(n/2) + O(1)

展开递归:

T(n)=T(n/4)+O(1)+O(1)=T(n/8)+O(1)+O(1)+O(1)=…T(n) = T(n/4) + O(1) + O(1) = T(n/8) + O(1) + O(1) + O(1) = \dots

直到搜索范围缩小到 1,即 n/2k=1n/2^k = 1,解得:

k=log⁡2nk = \log_2 n

因此,最坏情况下的时间复杂度是:

O(log⁡n)O(\log n)

3. 平均情况(Average Case)

在没有额外信息的情况下,平均情况下也需要进行大约 O(log⁡n) 级别的比较,因此平均时间复杂度也是:

O(log⁡n)

总结

情况时间复杂度
最好情况O(1)O(1)
最坏情况O(log⁡n)O(\log n)
平均情况O(log⁡n)O(\log n)

二分查找的时间复杂度远优于线性查找(O(n)),但前提是数据必须是有序的,否则需要先进行排序(如快速排序 O(nlog⁡n)),这会影响整体效率。

相关文章:

算法基础学习——二分查找(附带Java模板)

有单调性的数列一定可以使用二分&#xff0c;没有单调性的题目也可能可以使用二分&#xff1b; &#xff08;一&#xff09;整数二分 二分的本质&#xff1a; 在某个整数区间内&#xff0c;存在某种性质使得区间内左半边的数都不满足该性质&#xff1b;而右半边的数都满足该性…...

【llm对话系统】大模型源码分析之llama模型的long context更长上下文支持

1. 引言 Llama模型的一个重要特性是支持长上下文处理。本文将深入分析Llama源码中实现长上下文的关键技术点&#xff0c;包括位置编码(position embedding)的外推方法、注意力机制的优化等。我们将通过详细的代码解析来理解其实现原理。 2. 位置编码的外推实现 2.1 旋转位置…...

单片机基础模块学习——NE555芯片

一、NE555电路图 NE555也称555定时器,本文主要利用NE555产生方波发生电路。整个电路相当于频率可调的方波发生器。 通过调整电位器的阻值,方波的频率也随之改变。 RB3在开发板的位置如下图 测量方波信号的引脚为SIGHAL,由上面的电路图可知,NE555已经构成完整的方波发生电…...

Hive:struct数据类型,内置函数(日期,字符串,类型转换,数学)

struct STRUCT&#xff08;结构体&#xff09;是一种复合数据类型&#xff0c;它允许你将多个字段组合成一个单一的值, 常用于处理嵌套数据&#xff0c;例如当你需要在一个表中存储有关另一个实体的信息时。你可以使用 STRUCT 函数来创建一个结构体。STRUCT 函数接受多个参数&…...

最优化问题 - 内点法

以下是一种循序推理的方式&#xff0c;来帮助你从基础概念出发&#xff0c;理解 内点法&#xff08;Interior-Point Method, IPM&#xff09; 是什么、为什么要用它&#xff0c;以及它是如何工作的。 1. 问题起点&#xff1a;带不等式约束的优化 假设你有一个带不等式约束的优…...

vim交换文件的工作原理

在vim中&#xff0c;交换文件是一个临时文件&#xff0c;当我们使用vim打开一个文件进行编辑&#xff08;一定得是做出了修改才会产生交换文件&#xff09;时候&#xff0c;vim就会自动创建一个交换文件&#xff0c;而之后我们对于文件的一系列修改都是在交换文件中进行的&…...

CISCO路由基础全集

第一章&#xff1a;交换机的工作原理和基本技能_交换机有操作系统吗-CSDN博客文章浏览阅读1.1k次&#xff0c;点赞24次&#xff0c;收藏24次。交换机可看成是一台特殊的计算机&#xff0c;同样有CPU、存储介质和操作系统&#xff0c;只是与计算机的稍有不同。作为数据交换设备&…...

网络直播时代的营销新策略:基于受众分析与开源AI智能名片2+1链动模式S2B2C商城小程序源码的探索

摘要&#xff1a;随着互联网技术的飞速发展&#xff0c;网络直播作为一种新兴的、极具影响力的媒体形式&#xff0c;正逐渐改变着人们的娱乐方式、消费习惯乃至社交模式。据中国互联网络信息中心数据显示&#xff0c;网络直播用户规模已达到3.25亿&#xff0c;占网民总数的45.8…...

2024年终总结——今年是蜕变的一年

2024年终总结 摘要前因转折找工作工作的成长人生的意义 摘要 2024我从国企出来&#xff0c;兜兜转转还是去了北京&#xff0c;一边是工资低、感情受挫&#xff0c;一边是压力大、项目经历少&#xff0c;让我一度找不到自己梦寐以求的工作&#xff0c;我投了一家又一家&#xff…...

AutoDL 云服务器:普通 用户 miniconda 配置

AutoDL 初始状态下只有root用户&#xff0c;miniconda 安装在root用户目录下 /// 增加普通用户 rootautodl-container-1c0641804d-5bb7040c:~/Desktop# apt updaterootautodl-container-1c0641804d-5bb7040c:~/Desktop# apt install sudorootautodl-container-1c0641804d-5…...

渲染流程概述

渲染流程包括 CPU应用程序端渲染逻辑 和 GPU渲染管线 一、CPU应用程序端渲染逻辑 剔除操作对物体进行渲染排序打包数据调用Shader SetPassCall 和 Drawcall 1.剔除操作 视椎体剔除 &#xff08;给物体一个包围盒&#xff0c;利用包围盒和摄像机的视椎体进行碰撞检测&#xf…...

前端力扣刷题 | 4:hot100之 子串

560. 和为K的子数组 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例&#xff1a; 输入&#xff1a;nums [1,1,1], k 2 输出&#xff1a;2 法一&#xff1a;暴力法 var subar…...

Julia 之 @btime 精准测量详解

Julia 语言因其高性能和易用性在科学计算、数据分析等领域获得了广泛关注。在性能优化中&#xff0c;精准测量代码执行时间是至关重要的任务&#xff0c;而 Julia 提供了强大的工具 btime 来辅助这一任务。本文将围绕 Julia 的 btime 来展开&#xff0c;帮助读者深入理解并高效…...

【Django教程】用户管理系统

Get Started With Django User Management 开始使用Django用户管理 By the end of this tutorial, you’ll understand that: 在本教程结束时&#xff0c;您将了解&#xff1a; Django’s user authentication is a built-in authentication system that comes with pre-conf…...

【机器学习】自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测

一、使用pytorch框架实现逻辑回归 1. 数据部分&#xff1a; 首先自定义了一个简单的数据集&#xff0c;特征 X 是 100 个随机样本&#xff0c;每个样本一个特征&#xff0c;目标值 y 基于线性关系并添加了噪声。将 numpy 数组转换为 PyTorch 张量&#xff0c;方便后续在模型中…...

C语言连接Mysql

目录 C语言连接Mysql下载 mysql 开发库 方法介绍mysql_init()mysql_real_connect()mysql_query()mysql_store_result()mysql_num_fields()mysql_fetch_fields()mysql_fetch_row()mysql_free_result()mysql_close() 完整代码 C语言连接Mysql 下载 mysql 开发库 方法一&#xf…...

Windows上通过Git Bash激活Anaconda

在Windows上配置完Anaconda后&#xff0c;普遍通过Anaconda Prompt激活虚拟环境并执行Python&#xff0c;如下图所示&#xff1a; 有时需要连续执行多个python脚本时&#xff0c;直接在Anaconda Prompt下可以通过在以下方式&#xff0c;即命令间通过&&连接&#xff0c;…...

面试经典150题——图

文章目录 1、岛屿数量1.1 题目链接1.2 题目描述1.3 解题代码1.4 解题思路 2、被围绕的区域2.1 题目链接2.2 题目描述2.3 解题代码2.4 解题思路 3、克隆图3.1 题目链接3.2 题目描述3.3 解题代码3.4 解题思路 4、除法求值4.1 题目链接4.2 题目描述4.3 解题代码4.4 解题思路 5、课…...

学习数据结构(1)时间复杂度

1.数据结构和算法 &#xff08;1&#xff09;数据结构是计算机存储、组织数据的方式&#xff0c;指相互之间存在⼀种或多种特定关系的数据元素的集合 &#xff08;2&#xff09;算法就是定义良好的计算过程&#xff0c;取一个或一组的值为输入&#xff0c;并产生出一个或一组…...

项目集成GateWay

文章目录 1.环境搭建1.创建sunrays-common-cloud-gateway-starter模块2.目录结构3.自动配置1.GateWayAutoConfiguration.java2.spring.factories 3.pom.xml4.注意&#xff1a;GateWay不能跟Web一起引入&#xff01; 1.环境搭建 1.创建sunrays-common-cloud-gateway-starter模块…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

springboot 日志类切面,接口成功记录日志,失败不记录

springboot 日志类切面&#xff0c;接口成功记录日志&#xff0c;失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...

【深度学习新浪潮】什么是credit assignment problem?

Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...

React核心概念:State是什么?如何用useState管理组件自己的数据?

系列回顾&#xff1a; 在上一篇《React入门第一步》中&#xff0c;我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目&#xff0c;并修改了App.jsx组件&#xff0c;让页面显示出我们想要的文字。但是&#xff0c;那个页面是“死”的&#xff0c;它只是静态…...