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

news2024/12/26 20:45:49

在这里插入图片描述

前言

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

一. 原理讲解

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

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

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

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

二. 二分查找

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;
            }//更新left
            else
            {
                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;
            }//更新left
            else
            {
                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;
            }//更新left
            else
            {
                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.coloradmin.cn/o/2251615.html

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

相关文章

【软件各类应用解决方案】ERP企业资源管理系统整体解决方案,采购管理方案,仓库管理方案,财务管理方案,人力管理方案,资产管理方案,对账管理(word完整版)

目录 第一部分 概述 第二部分 方案介绍 第三部分 系统业务流程 3.1 关键需求概括分析 3.1.1 销售管理方面 3.1.2 采购管理方面 3.1.3 仓库管理方面 3.1.4 财务管理方面 3.1.5 人力资源方面 3.2 关键需求具体分析 3.2.1 财务管理 3.2.1.1会计凭证解决 3.2.1.2钞…

实验二 选择结构程序设计

实验名称 实验二 选择结构程序设计 实验目的 &#xff08;1&#xff09;掌握关系运算符和逻辑运算符的使用方法&#xff0c;能够表达复杂的逻辑条件。 &#xff08;2&#xff09;掌握if语句的使用方法&#xff0c;掌握多重条件下的if语句嵌套使用。 &#xff08;3&#xff09;…

第33周:运动鞋识别(Tensorflow实战第五周)

目录 前言 一、前期工作 1.1 设置GPU 1.2 导入数据 1.3 查看数据 二、数据预处理 2.1 加载数据 2.2 可视化数据 2.3 再次检查数据 2.4 配置数据集 2.4.1 基本概念介绍 2.4.2 代码完成 三、构建CNN网络 四、训练模型 4.1 设置动态学习率 4.2 早停与保存最佳模型…

Robot Screw Theory (Product of Exponentials)机器人螺旋理论(指数积)

Screw Theory 螺旋理论 Screw theory uses the fact that every rigid body transformation can be expressed by a rotational and translational movement.螺旋理论利用了每个刚体变换都可以通过旋转和平移运动来表示这一事实。 Robert Ball developed the theory in 19th ce…

【maven-5】Maven 项目构建的生命周期:深入理解与应用

1. 生命周期是什么 ​在Maven出现之前&#xff0c;项目构建的生命周期就已经存在&#xff0c;软件开发人员每天都在对项目进行清理&#xff0c;编译&#xff0c;测试及部署。虽然大家都在不停地做构建工作&#xff0c;但公司和公司间&#xff0c;项目和项目间&#xff0c;往往…

skywalking 配置elasticsearch持久化

下载和启动elasticsearch elasticsearch-7.17.25-linux-x86_64.tar.gz&#xff0c;解密文件tar -xvf elasticsearch-7.17.25-linux-x86_64.tar.gz 进入到bin目录&#xff0c;启动 elasticsearch -d 后台运行 下载skywalking服务包 apache-skywalking-apm-9.3.0.tar.gz&#x…

MySQL 复合查询

实际开发中往往数据来自不同的表&#xff0c;所以需要多表查询。本节我们用一个简单的公司管理系统&#xff0c;有三张表EMP,DEPT,SALGRADE 来演示如何进行多表查询。表结构的代码以及插入的数据如下&#xff1a; DROP database IF EXISTS scott; CREATE database IF NOT EXIST…

数据集-目标检测系列- 海边漫步锻炼人检测数据集 person >> DataBall

数据集-目标检测系列- 海边漫步锻炼人检测数据集 person >> DataBall DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 需要更多数据资源和技术解决方案&#xff0c;知识星球&#xff1a; “DataBall - X 数据球…

【汇编语言】call 和 ret 指令(三) —— 深度解析汇编语言中的批量数据传递与寄存器冲突

文章目录 前言1. 批量数据的传递1.1 存在的问题1.2 如何解决这个问题1.3 示例演示1.3.1 问题说明1.3.2 程序实现 2. 寄存器冲突问题的引入2.1 问题引入2.2 分析与解决问题2.2.1 字符串定义方式2.2.2 分析子程序功能2.2.3 得到子程序代码 2.3 子程序的应用2.3.1 示例12.3.2 示例…

刷题日常(找到字符串中所有字母异位词,​ 和为 K 的子数组​,​ 滑动窗口最大值​,全排列)

找到字符串中所有字母异位词 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 题目分析&#xff1a; 1.将p里面的字符先丢进一个hash1中&#xff0c;只需要在S字符里面找到多少个和他相同的has…

Git 快速入门:全面了解与安装步骤

Git 快速入门&#xff1a;全面了解与安装步骤 一、关于Git 1.1 简介 Git 是一个开源的分布式版本控制系统&#xff0c;由 Linus Torvalds 于 2005 年创建&#xff0c;最初是为了更好地管理 Linux 内核开发而设计。 Git用于跟踪计算机文件的变化&#xff0c;特别是源代码文件…

私有库gitea安装

一 gitea是什么 Gitea是一款自助Git服务&#xff0c;简单来说&#xff0c;就是可以一个私有的github。 搭建很容易。 Gitea依赖于Git。 类似Gitea的还有GitHub、Gitee、GitLab等。 以下是安装步骤。 二 安装sqilite 参考&#xff1a; 在windows上安装sqlite 三 安装git…

[CTF/网络安全] 攻防世界 upload1 解题详析

[CTF/网络安全] 攻防世界 upload1 解题详析 考察文件上传&#xff0c;具体原理及姿势不再赘述。 姿势 在txt中写入一句话木马<?php eval($_POST[qiu]);?> 回显如下&#xff1a; 查看源代码&#xff1a; Array.prototype.contains function (obj) { var i this.…

基于HTML+CSS的房地产销售网站设计与实现

摘 要 房地产销售系统&#xff0c;在二十年来互联网时代下有着巨大的意义&#xff0c;随着互联网不断的发展扩大&#xff0c;一个方便直 观的房地产管理系统的网站开发是多么地有意义&#xff0c;不仅打破了传统的线下看房&#xff0c;线下获取资讯&#xff0c;也给房地产从业…

说说Elasticsearch拼写纠错是如何实现的?

大家好&#xff0c;我是锋哥。今天分享关于【说说Elasticsearch拼写纠错是如何实现的&#xff1f;】面试题。希望对大家有帮助&#xff1b; 说说Elasticsearch拼写纠错是如何实现的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Elasticsearch 中&…

如何把产品3D模型放到网站上进行3D展示或3D互动?

要将产品3D模型放到网站上进行3D展示或3D互动&#xff0c;可以按照以下步骤进行&#xff1a; 一、准备3D模型 使用3D建模软件&#xff08;如3ds Max、Maya、Blender、C4D等&#xff09;制作好产品的3D模型。 确保3D模型的格式是网站或平台所支持的&#xff0c;常见的格式包括…

SpringBoot集成Flowable

一、工作流介绍 1、概念 通过计算机对业务流程的自动化管理。工作流是建立在业务流程的基础上&#xff0c;一个软件的系统核心根本上还是系统的业务流程&#xff0c;工作流只是协助进行业务流程管理。 解决的是&#xff1a;在多个参与者之间按照某种预定义的规则自动进行传递文…

1-1 Gerrit实用指南

注&#xff1a;学习gerrit需要拥有git相关知识&#xff0c;如果没有学习过git请先回顾git相关知识点 黑马程序员git教程 一小时学会git git参考博客 git 实操博客 1.0 定义 Gerrit 是一个基于 Web 的代码审查系统&#xff0c;它使用 Git 作为底层版本控制系统。Gerrit 的主要功…

鸿蒙开发:自定义一个任意位置弹出的Dialog

前言 鸿蒙开发中&#xff0c;一直有个问题困扰着自己&#xff0c;想必也困扰着大多数开发者&#xff0c;那就是&#xff0c;系统提供的dialog自定义弹窗&#xff0c;无法实现在任意位置进行弹出&#xff0c;仅限于CustomDialog和Component struct的成员变量&#xff0c;这就导致…

Matlab模块From Workspace使用数据类型说明

Matlab原文连接&#xff1a;Load Data Using the From Workspace Block 模型&#xff1a; 从信号来源的数据&#xff1a; timeseries 数据&#xff1a; sampleTime 0.01; numSteps 1001;time sampleTime*[0:(numSteps-1)]; time time;data sin(2*pi/3*time);simin time…