二分算法——优选算法

个人主页:敲上瘾-CSDN博客

个人专栏:游戏、数据结构、c语言基础、c++学习、算法

        本章我们来学习的是二分查找算法,二分算法的应用非常广泛,不仅限于数组查找,还可以用于解决各种搜索问题、查找极值问题等。在数据结构和算法中,它是基础且重要的算法之一。

接下来我准备了三个题来引出并学习该算法,最后来做总结。

目录

一、二分查找

1.题目解析

2.算法原理

3.代码编写

二、查找元素的首末位置

1.题目解析

2.算法原理

3.代码编写

三、寻找峰值

1.题目解析

2.算法原理

3.代码编写

四、总结


一、二分查找

1.题目解析

        该题目要求是给一个元素target然后在升序数组nums中找到该元素的下标,若不存在则返回-1。题目要求简单易懂就不再多讲,这里要注意两个点:(1)、数组是升序的。(2)、需要返回的是元素下标。

2.算法原理

        对于该题最容易想到的解法就是把数组从头到尾遍历一遍,时间复杂度为O(N)。

        解法二:因为这个数组是有序的所以我们可以用二分的思想,首先使用三个指针(这里指的是数组的下标)left,right,mid,其中left和right维护一段区间,把目标值锁定到[left,right]区间内。mid表示区间的中心下标,把区间一分为二。

        接下来锁定target的位置:如果target小于mid下标指向的元素,那么因为数组是升序,所以target一定在区间[left,mid]中,即right更新为mid,然后更新mid( mid=left+(right-left)/2 )。              如果target大于mid指向元素,那么target一定在区间[mid,right]中,即把left更新为mid,然后更新mid。重复操作直到left>right。

如下:

该算法的时间复杂度为logN,证明如下:

3.代码编写

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

二、查找元素的首末位置

1.题目解析

        该题的题目要求与上一题类似,都是在升序数组中查找元素,不过该题查找的是元素第一次出现的位置和最后一次出现的位置。这里还要求时间复杂度为O(logN),这里就很明显地提示了该题要使用二分算法。

2.算法原理

        同样的此题可以使用暴力枚举来解决,不过时间复杂度为O(N),根据上题的经验这里我们还是考虑使用二分法。不过也很容易发现把上面的算法原模原样搬过来是解决不了该道题的,我们只能找到target元素的是无法锁定它第一次出现的位置和最后一次出现的位置。我们可以用以下解法:

左边界查找:

        当mid指向的元素为target的时候,不用返回,而是让right更新为mid,mid指向元素大于target时同样更新right为mid,即可以合并为

        if(nums[mid]>=target)   right=mid;

当mid指向元素小于target时left更新为mid+1,重复该操作就可以把数组右边的target忽略,锁定最左边的target。这里做循环的时候需要注意循环条件不能是left<=rigth,如果是left<=right就可能使mid一直赋值给right从而进入死循环,所以我们使用left<right

右边界查找:

        当mid指向的元素为target的时候,不用返回,而是让left更新为mid,mid指向元素小于target时同样更新left为mid,即可以合并为

        if(nums[mid]<=target)   left=mid;

当mid指向元素大于target时right更新为mid-1,重复该操作就可以把数组左边的target忽略,锁定最右边的target。这里做循环的时候同样需要注意循环条件只能是left<rigth。

注意:当元素只有两个时使用mid=left+(right-left)/2计算的mid就是第一个元素,那么也就是mid==left,如果mid指向的元素为target时把mid赋值给left(即left=mid)相当于什么也没干,程序同样会进入死循环。所以我们使用mid=left+(right-left+1)/2计算mid。

        以上的两个查找法几乎可以解决所有的二分算法题,可以作为一个模板记忆,在总结部分我会给出模板。

3.代码编写

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;
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if(nums[mid]>=target) right=mid;
            else left=mid+1;
        }
        if(nums[left]!=target) return {-1,-1};
        int n=left;
        right=nums.size()-1;
        while(left<right)
        {
            int mid=left+(right-left+1)/2;
            if(nums[mid]<=target) left=mid;
            else right=mid-1;
        }
        return {n,left};
    }
};

三、寻找峰值

1.题目解析

该题要求我们返回任意峰值,比如把数组元素抽象成连续的数据如下:

需要返回以上红圈部分的任意一点, 也就是该元素至少要满足它左边的第一个元素和右边的第一个元素都要小于它。

注意:题目给的信息nums[-1]和nums[n]为负无穷,所以不要忽略以下情况:

2.算法原理

        这题同样可以使用暴力枚举,时间复杂度为O(N),该解法就不再多讲。

        这个题与上两个题有一个很大的区别是该数组并不是有序的,但是没关系该题同样可以使用二分的思想,注意很多人会误认为二分算法只能用在有序的数组中,而事实并不局限于此,只需要找到数据的二段性即可,如该题我们可以这样:

        该方法也就是上一题的右边界查找,当然也可以使用左边界查找的方法,但用朴素的二分查找解决不了该题。

3.代码编写

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

四、总结

1、二分算法并不局限于数组有序,只要找到数据的二段性即可使用二分算法。

2、二分算法模板

2.1.朴素二分模板

while(left<=right)
{
    int mid=left+(right-left)/2;
    if(...) left=mid+1;
    else if(...) right=mid-1;
    else ...
}

2.2.左边界查找模板

while(left<right)
{
    int mid=left+(right-left)/2;
    if(...) left=mid+1;
    else right=mid;
}

2.3.右边界查找模板

while(left<right)
{
    int mid=left+(right-left+1)/2;
    if(...) left=mid;
    else right=mid-1;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

海外仓商品退换货管理:选择系统为何至关重要?

随着跨境电商的蓬勃发展&#xff0c;退换货问题成为了卖家们不得不面对的挑战。退换货处理不仅繁琐&#xff0c;而且对效率和服务质量的要求极高。因此&#xff0c;许多卖家选择海外仓来简化退换货流程。然而&#xff0c;海外仓在处理退换货时同样面临诸多难题&#xff0c;涉及…

openeuler 22.03 lts sp4 使用 kubeadm 部署 k8s-v1.28.2 高可用集群

文章目录 [toc]废话篇这篇文章什么时候写的为什么是 openeuler为什么是 22.03 lts sp4高可用架构题外话 干活篇环境介绍系统初始化相关关闭防火墙关闭 selinux关闭 swap开启内核模块开启模块自动加载服务 sysctl 内核参数调整清空 iptables 规则安装各种依赖和工具修改 .bashrc…

【uni-app】小兔鲜项目-基础架构-请求和上传文件拦截器

注意事项 uni.request 请求封装 请求和上传文件拦截器 uniapp 拦截器&#xff1a; uni.addInterceptor 接口说明&#xff1a;接口文档 实现需求 拼接基础地址设置超时时间添加请求头标识添加 token 参考代码 // src/utils/http.ts// 请求基地址 const baseURL https://pca…

ArcGIS Desktop使用入门(三)图层右键工具——拓扑(下篇:地理数据库拓扑)

系列文章目录 ArcGIS Desktop使用入门&#xff08;一&#xff09;软件初认识 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——标准工具 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——编辑器 ArcGIS Desktop使用入门&#xff08;二&#x…

浅析OceanBase数据库的向量化执行引擎

本篇博客是偏数据库系统概念性的内容&#xff0c;不会深入到 OceanBase 中各个算子和表达式的在向量化中的详细设计和实现。 背景 为了提升OceanBase社区版用户解决问题的效率&#xff0c;OceanBase官方不久前推出了《OceanBase 从入门到实践》系列课程。在第七期直播课程后&a…

Llama 3.1 技术研究报告-2

3.3 基础设施、扩展性和效率 我们描述了⽀持Llama 3 405B⼤规模预训练的硬件和基础设施&#xff0c;并讨论了⼏项优化措施&#xff0c;这些措施提⾼了训练效率。 3.3.1 训练基础设施 Llama 1和2模型在Meta的AI研究超级集群&#xff08;Lee和Sengupta&#xff0c;2022&#x…

软件设计师:01计算机组成与结构

文章目录 一、校验码1.奇偶校验码2.海明码3.循环冗余检验码 二、原码反码补码移码三、浮点数表示法1.浮点数相加时 四、寻址方式五、CPU1.访问速度2.cpu的组成 六、RISC和CISC&#xff08;<font color red>只用记住不同就可以&#xff09;七、冗余技术1.结构冗余2.信息冗…

2018年国赛高教杯数学建模D题汽车总装线的配置问题解题全过程文档及程序

2018年国赛高教杯数学建模 D题 汽车总装线的配置问题 一&#xff0e;问题背景   某汽车公司生产多种型号的汽车&#xff0c;每种型号由品牌、配置、动力、驱动、颜色5种属性确定。品牌分为A1和A2两种&#xff0c;配置分为B1、B2、B3、B4、B5和B6六种&#xff0c;动力分为汽油…

2024年陕西省安全员B证证模拟考试题库及陕西省安全员B证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年陕西省安全员B证证模拟考试题库及陕西省安全员B证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;陕西省安全员B证证模拟考试题库是根据陕西省安全员B证最新版教材&#xff0c;陕西省安全员B证大纲整理…

C语言 | Leetcode C语言题解之第424题替换后的最长重复字符

题目&#xff1a; 题解&#xff1a; int characterReplacement(char* s, int k) {int num[26];memset(num, 0, sizeof(num));int n strlen(s);int maxn 0;int left 0, right 0;while (right < n) {num[s[right] - A];maxn fmax(maxn, num[s[right] - A]);if (right - …

Oracle日常运维(一线DBA必备技能)(二)

List item 本篇接上篇&#xff0c;接着介绍Oracle DB几类重要文件的日常管理&#xff0c;和作为DBA需要掌握针对这些文件的哪些操作。本篇将重点介绍参数文件和控制文件&#xff0c;数据文件是和业务息息相关的文件&#xff0c;在后续的数据库备份恢复&#xff0c;优化篇将会针…

【Spring Cloud Alibaba】Nacos

【Spring Cloud Alibaba】Nacos 1. 什么是Nacos&#xff0c;它都能干什么&#xff1f;1.1 注册中心演变及其思想1.2 Nacos Discovery1.3 远程调用流程图1.4 一个微服务的流程1.4 常用注册中心对比 2. Nacos Server部署3. Nacos Client搭建附录 1. 什么是Nacos&#xff0c;它都能…

【机器学习】11——矩阵求导

机器学习11——矩阵求导 打公式不太好标注&#xff0c;全图警告&#xff01;&#xff01;&#xff01; 文章目录 机器学习11——矩阵求导1.1标量对向量1.2标量对矩阵2.1向量对标量2.2向量对向量2.3向量对矩阵 1.1标量对向量 1.2标量对矩阵 X是m*n的矩阵&#xff0c;不严谨&am…

鸿蒙OpenHarmony【轻量系统内核扩展组件(C++支持)】子系统开发

C支持 基本概念 C作为目前使用最广泛的编程语言之一&#xff0c;支持类、封装、重载等特性&#xff0c;是在C语言基础上开发的一种面向对象的编程语言。 运行机制 C代码的识别主要由编译器支持&#xff0c;系统主要对全局对象进行构造函数调用&#xff0c;进行初始化操作。…

数字病理图像处理:分割、合成与数据增强研究|顶刊精析·24-09-20

小罗碎碎念 今日精析&#xff1a;Medical Image Analysis 这篇文章介绍了一种结合了先进分割模型和生成对抗网络的病理切片图像分析流程&#xff0c;用于提高癌症诊断的准确性和效率。 作者角色姓名单位名称&#xff08;中文&#xff09;第一作者Muhammad Jehanzaib博阿齐奇大学…

【高效且应用广泛的排序 —— 快速排序算法】

高效且应用广泛的排序 —— 快速排序算法 快速排序是一种常用的排序算法&#xff0c;主要采用分治的思想。以下是对快速排序算法的详细介绍及代码示例&#xff1a; 快速排序的基本思路是&#xff0c;每次将一个位置上的数据归位&#xff0c;使得该数左边的所有数据都比该数小…

构建高效企业客户管理系统:SpringBoot应用

1 绪论 1.1研究背景 随着网络不断的普及发展&#xff0c;企业客户管理系统依靠网络技术的支持得到了快速的发展&#xff0c;首先要从员工的实际需求出发&#xff0c;通过了解员工的需求开发出具有针对性的首页、个人中心、员工管理、客户信息管理、行业类型管理、项目信息管理、…

自动化测试概念篇

目录 一、自动化 1.自动化概念 1.1 回归测试 2. 自动化分类 2.1 接口自动化 2.2 UI自动化 3. 自动化测试金字塔 二、web自动化测试 1. 驱动 1.1 安装驱动管理 1.2 selenium库 三、selenium 1. 一个简单的web自动化示例 2. selenium驱动浏览器的工作原理 一、自动化…

【Linux系统编程】第二十二弹---操作系统核心概念:进程创建与终止机制详解

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、进程创建 1.1、fork函数重识 1.2、fork函数返回值 1.3、写时拷贝 1.4、fork常规用法 1.5、fork调用失败的原因 2、进程…

图像压缩编码(4)--H.26x系列视频压缩编码_2

目录 H.261 视频编码标准 H.261的编码与解码 1&#xff09; 帧内/帧间编码 2&#xff09;运动补偿 3&#xff09;量化 4&#xff09;环路滤波器 5&#xff09;缓存器 压缩数据的分层 数据复用结构 H.264的编码与解码 H.261 视频编码标准 实际应用时&#xff0c;要求有…