二分法篇——于上下边界的扭转压缩间,窥见正解辉映之光(1)

在这里插入图片描述

前言

二分法,这一看似简单却又充满哲理的算法,犹如一道精巧的数学之门,带领我们在问题的迷雾中找到清晰的道路。它的名字虽简单,却深藏着智慧的光辉。在科学的浩瀚星空中,二分法如一颗璀璨的星辰,指引着我们如何高效地寻找答案。本文将带领大家走进二分法的世界,探讨它的原理、应用及其在各种问题中的深远影响。

一. 原理讲解

二分法,顾名思义,是将一个问题或区间不断地分成两个部分,逐步逼近目标答案。最常见的应用是求解有序数列中的某个元素,或者求解某个函数的零点。
其基本思路如下:

  • 初始化区间: 在一维空间中,选择一个包含目标值的初始区间。
  • 逐步缩小区间: 将区间分为两半,判断目标值是否在左半区间或右半区间中,根据判断结果进一步缩小搜索区间。
  • 终止条件: 直到找到目标值或区间缩小到足够小为止。

这种“分而治之”的策略,极大地提高了搜索效率,尤其在处理大规模数据时,具有显著的优势。

下面我们将结合具体题型进行二分法的使用与讲解。

二. 二分查找

2.1 题目链接:https://leetcode.cn/problems/binary-search/description/

2.2 题目分析:

  1. 题目中给出一个升序排列的数组,其中元素有正有负
  2. 要求查找并返回数组内与target相同的元素的下标
  3. 如果不存在,则返回-1
  4. nums内的所有元素都不重复

2.3 思路讲解

暴力解法:

此题较为简单,查找目标值,直接遍历即可,且数据量不大,应该不会超时,不再给出示例代码。

二分法:

  1. 根据上文提到的原理可知,我们首先需要确定左右边界,因此令left=0,right=nums.size()-1.
  2. 由于该题数组为升序排列,二分之后具有二段性,即mid左侧区间内所有元素都小于mid,而mid右侧区间内所有元素都大于mid
  3. 因此我们进行while循环,逐次二分判断即可。如果循环期间内未成功返回target的下标,说明不存在,反之,返回mid即可。

代码实现:

class Solution {
public:int search(vector<int>& nums, int target) {int left=0,right=nums.size()-1;//确定左右边界//由于两个指针相交时还未判断是否等于target,因此需要取等号while(left<=right){int mid=(left+right)/2;if(nums[mid]>target){right=mid-1;}//更新右边界else if(nums[mid]<target){left=mid+1;}//更新左区间else{return mid;}}return -1;}
};

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

3.1 题目链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/description/

3.2 题目分析:

  1. 题目给出按照升序排列的数组nums以及目标值target,要求返回target在数组内的起始下标和结束下标。
  2. 如果不存在,则返回{-1,-1}
  3. 时间复杂度要求为logn。

3.3 思路讲解:

问题:时间复杂度的要求和数组的二段性已经很明显的提示我们需要使用二分法,可是二分法我们只尝试过查找单个target,面对一连串的target,我们又该如何处理呢?

虽然我们要查找的target是一串区间,但是数组仍满足二段性,在target起始区间的左侧,所有元素均小于target,而在target结束区间的右侧,所有元素均大于target。

因此,我们使用两次二分,分别查找该区间的左右边界即可,具体步骤如下:

  • 仍旧令left=0,right=nums.size()-1,确定左右区间进行二分查找

  • 查找target的起始下标(左边界)如图:

  • 在这里插入图片描述

  • 查找target的结束下标(右边界)如图:

  • 在这里插入图片描述

代码实现:

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;int begin=0;//查找左边界while(left<right){int mid=left+(right-left)/2;if(nums[mid]<target){left=mid+1;}//更新leftelse{right=mid;}//更新right}if(nums[left]!=target){return {-1,-1};}//若左边界未查找成功,说明不存在target,直接返回begin=left;//查找成功,更新左边界//查找右边界right=nums.size()-1;//将right恢复为初始状态while(left<right){int mid=left+(right-left+1)/2;if(nums[mid]==target){left=mid;}//更新leftelse{right=mid-1;}//更新right}return {begin,right};}
};

四. x的平方根

4.1 题目链接:https://leetcode.cn/problems/sqrtx/description/

4.2 题目分析:

  • 给出x,要求计算x的算术平方根
  • 结果只保留整数部分,而非按照四舍五入规则
  • x的范围很大,使用int会存在越界情况
  • x可能为0,此时应特殊处理

4.3 思路讲解:

我们可假设目标值为target,那么该题所有答案都在[0,n]的这个数组内。

且[0,target]内,所有元素的平方和均小于x,[target,x]内,所有元素的平方和均大于x,即满足二段性,因此可考虑使用二分法进行解决。
具体步骤如下:

  1. 令left=1,right=x,确实左右区间进行遍历
  2. 进行取中点操作,mid=left+(right-left+1)/2,如果mid*mid>x,说明target在[left,mid]内,right更新为mid-1.
  3. 如果mid*mid<=x,说明target在[left,mid]内,left更新为mid。
  4. 进行循环遍历,最终left即为所求。

4.4 代码实现:

class Solution {
public:int mySqrt(int x) {int left=1,right=x;if(x==0){return 0;}while(left<right){long long mid=left+(right-left+1)/2;//防止越界if(mid*mid<=x){left=mid;}//更新leftelse{right=mid-1;}//更新right}return left;}
};

五. 山脉数组的峰顶索引

5.1 题目链接:https://leetcode.cn/problems/peak-index-in-a-mountain-array/description/

5.2 题目分析:

  • 该数组呈山脉分布,设峰值元素为target,则[0,target]内元素递增,[target,n-1]内元素递减,要求返回峰值元素的下标
  • 时间复杂度要求为logn

5.3 思路讲解:

由上述分析不难发现可是用二分法。

  1. 令left=1,right=nums.size()-2,作为左右边界。
    注意:此处如此初始化是因为至少需要3个元素才能组成一个山峰,因此下标为0和下标为n-1的元素不可能为峰顶元素
  2. 求取中点mid=left+(right-left+1)/2,并令nums[mid]与nums[mid-1]进行比较。
  • 如果nums[mid]>=nums[mid-1],说明mid处在上升区间内,target一定位于[mid,right]内,因此更新left为mid
  • 如果nums[mid]<nums[mid-1],说明mid处在下降区间内,target一定位于[left,mid]内,因此更新right为mid-1
  1. while循环二分操作,最后left即为所求target

5.4 代码实现:

class Solution {
public:int peakIndexInMountainArray(vector<int>& arr) {int left=1,right=arr.size()-2;//峰顶元素即为最大值while(left<right){int mid=left+(right-left+1)/2;if(arr[mid]>arr[mid-1]){left=mid;}//mid在上升区间内else {right=mid-1;}}return left;}
};

六. 小结

6.1 局限性

尽管二分法在许多情况下都表现出极高的效率,但它也并非万能。在应用二分法时,要求数据必须是有序的,否则无法直接应用。此外,二分法在处理某些特殊类型的问题时,可能需要额外的技巧或调整。例如,求解无序数据中的元素时,二分法并不能直接使用,需要先进行排序或采取其他的算法。

6.2 时间复杂度

二分法的时间复杂度为 O(log n),这使得它在处理大规模数据时,具有非常高的效率。在最坏的情况下,每一步都将问题规模缩小一半,从而大大减少了运算的次数。与线性搜索相比,二分法能大幅度提高搜索效率,尤其是在数据量极大的情况下。

6.3 结语

二分法作为一种简单而高效的算法,已经成为计算机科学与数学中不可或缺的一部分。它不仅仅是一个算法工具,更是我们思考问题、解决问题的哲学。在这条“二分之间”的道路上,我们不仅找到了问题的解答,也探索到了求解问题的一种智慧。它教会我们,在复杂问题面前,不妨将问题拆解,逐步攻克,最终发现通往答案的光明之路。

本篇关于二分法的介绍就暂告一段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持斧正!!!
在这里插入图片描述

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

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

相关文章

基于 FFmpeg/Scrcpy 框架构建的一款高性能的安卓设备投屏管理工具-供大家学习研究参考

支持的投屏方式有:USB,WIFIADB,OTG,投屏之前需要开启开发者选项里面的USB调试。 主要功能有: 1.支持单个或多个设备投屏。 2.支持键鼠操控。 3.支持文字输入。 4.支持共享剪切板(可复制粘贴电脑端文字到手机端,也可导出手机剪切板到电脑端)。 5.支持视频图片上传,可单…

【论文笔记】A Token-level Contrastive Framework for Sign Language Translation

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: A Token-level Contrastiv…

ROS2教程 - 3 HelloWorld

更好的阅读体验&#xff1a;https://www.foooor.com 3 HelloWorld 下面从 HelloWorld 开始&#xff0c;讲解 ROS2 的开发。 ROS 开发主要使用 C 或 Python 实现&#xff0c;如果要实现的功能&#xff0c;对性能有要求&#xff0c;可以使用 C 实现&#xff0c;如果对性能没有…

洛谷 B3626 跳跃机器人 C语言 记忆化搜索

题目&#xff1a; https://www.luogu.com.cn/problem/B3626 题目描述 地上有一排格子&#xff0c;共 n 个位置。机器猫站在第一个格子上&#xff0c;需要取第 n 个格子里的东西。 机器猫当然不愿意自己跑过去&#xff0c;所以机器猫从口袋里掏出了一个机器人&#xff01;这…

【AI】Sklearn

长期更新&#xff0c;建议关注、收藏、点赞。 友情链接&#xff1a; AI中的数学_线代微积分概率论最优化 Python numpy_pandas_matplotlib_spicy 建议路线&#xff1a;机器学习->深度学习->强化学习 目录 预处理模型选择分类实例&#xff1a; 二分类比赛 网格搜索实例&…

⭐️ GitHub Star 数量前十的工作流项目

文章开始前&#xff0c;我们先做个小调查&#xff1a;在日常工作中&#xff0c;你会使用自动化工作流工具吗&#xff1f;&#x1f64b; 事实上&#xff0c;工作流工具已经变成了提升效率的关键。其实在此之前我们已经写过一篇博客&#xff0c;跟大家分享五个好用的工作流工具。…

Tree搜索二叉树、map和set_数据结构

数据结构专栏 如烟花般绚烂却又稍纵即逝的个人主页 本章讲述数据结构中搜索二叉树与HashMap的学习&#xff0c;感谢大家的支持&#xff01;欢迎大家踊跃评论&#xff0c;感谢大佬们的支持! 目录 搜索二叉树的概念二叉树搜索模拟实现搜索二叉树查找搜索二叉树插入搜索二叉树删除…

Swift实现高效链表排序:一步步解读

文章目录 前言摘要问题描述题解解题思路Swift 实现代码代码分析示例测试与结果 时间复杂度空间复杂度总结关于我们 前言 本题由于没有合适答案为以往遗留问题&#xff0c;最近有时间将以往遗留问题一一完善。 148. 排序链表 不积跬步&#xff0c;无以至千里&#xff1b;不积小流…

【开篇】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…

qt QAnimationDriver详解

1、概述 QAnimationDriver是Qt框架中提供的一个类&#xff0c;它主要用于自定义动画帧的时间控制和更新。通过继承和实现QAnimationDriver&#xff0c;开发者可以精确控制动画的时间步长和更新逻辑&#xff0c;从而实现丰富和灵活的动画效果。QAnimationDriver与QAbstractAnim…

何时在 SQL 中使用 CHAR、VARCHAR 和 VARCHAR(MAX)

在管理数据库表时&#xff0c;考虑 CHAR、VARCHAR 和 VARCHAR(MAX) 是必不可少的。此外&#xff0c;使用正确的工具&#xff08;例如dbForge Studio for SQL Server&#xff09; &#xff0c;与数据库相关的任务都会变得更加容易。它是针对 SQL Server 专业人员的强大的一体化解…

20241127 给typecho文章编辑附件 添加视频 图片预览

Typecho在写文章时&#xff0c;如果一次性上传太多张图片可能分不清哪张&#xff0c;因为附件没有略缩图&#xff0c;无法实时阅览图片&#xff0c;给文章插入图片时很不方便。 编辑admin/file-upload.php 大约十八行的位置 一个while 循环里面,这是在进行html元素更新操作,在合…

Linux命令系列-常见查看系统资源命令

Linux命令系列-常见查看命令 进程管理内存管理磁盘空间管理网络管理主机系统 摘要&#xff1a;本文将对linux系统上常见的查看系统各种资源的命令进行介绍&#xff0c;包括du&#xff0c;df&#xff0c;netstat等命令。所有这些命令都有相关实验截图&#xff0c;实验平台为ubun…

【Python网络爬虫笔记】6- 网络爬虫中的Requests库

一、概述 Requests 是一个用 Python 语言编写的、简洁且功能强大的 HTTP 库。它允许开发者方便地发送各种 HTTP 请求&#xff0c;如 GET、POST、PUT、DELETE 等&#xff0c;并且可以轻松地处理请求的响应。这个库在 Python 生态系统中被广泛使用&#xff0c;无论是简单的网页数…

SolarCube: 高分辨率太阳辐照预测基准数据集

太阳能作为清洁能源在减缓气候变化中的作用日益凸显&#xff0c;其稳定的供应对电网管理至关重要。然而&#xff0c;太阳辐照受云层和天气变化的影响波动较大&#xff0c;给光伏电力的管理带来挑战&#xff0c;尤其是在调度、储能和备用系统管理方面。因此&#xff0c;精确的太…

对拍详细使用方法

对拍的作用 对于我们在学校OJ&#xff0c;cf&#xff0c;牛客…各种只提供少量测试数据的题目&#xff0c;常常交上代码常常超时&#xff0c;能写出正确的暴力代码而题目要求的时间复杂度更低。然而这时你写出了能通过样例且时间复杂度更低的代码&#xff0c;但交上去就是错误…

玄机应急:Apache日志分析Mysql应急Redis应急

目录 第二章&#xff1a;Linux的Apache日志分析 1、提交当天访问次数最多的IP&#xff0c;即黑客IP 2、黑客使用的浏览器指纹是什么&#xff0c;提交指纹的md5 3、查看index.php页面被访问的次数&#xff0c;提交次数&#xff1a; 4、查看黑客IP访问了多少次&#xff0c;提…

使用easyexcel导出复杂模板,同时使用bean,map,list填充

背景 在使用easyexcel导出时&#xff0c;如果遇到一个模板中同时存在 一部分是实体类中的字段&#xff0c;另外部分是列表的字段&#xff0c;需要特殊处理一下&#xff0c;比如下面的模板&#xff1a; 这里面 user&#xff0c; addr 是实体类&#xff08;或者map&#xff09…

otter 扩展

参见otter官方的说明&#xff1a;数据处理自定义&#xff0c;比如Extract , Transform的数据处理. 目前Select/Load不支持数据自定义处理。 Extract模块&#xff1a; 1.EventProcessor : 自定义数据处理&#xff0c;可以改变一条变更数据的任意内容。 2.FileResolver : 解决数…

STM32的CAN波特率计算

公式&#xff1a; CAN波特率 APB总线频率 / &#xff08;BRP分频器 1&#xff09;/ (SWJ BS1 BS2) SWJ一般为1。 例如STM32F407的&#xff0c;CAN1和CAN2都在在APB1下&#xff0c;频率是42000000 如果想配置成1M波特率&#xff0c;则计算公式为&#xff1a;