算法-二分专题

文章目录

  • 概念
  • 应用场景
  • 代码模板
  • OJ练习
    • 寻找指定元素1
      • 题目描述
      • 输入描述
      • 输出描述
      • 样例
      • 题解
    • 寻找指定元素2
      • 题目描述
      • 输入描述
      • 输出描述
      • 样例
      • 题解
    • 寻找指定元素3
      • 题目描述
      • 输入描述
      • 输出描述
      • 样例
      • 题解
    • 寻找指定元素4
      • 题目描述
      • 输入描述
      • 输出描述
      • 样例
      • 题解
    • 寻找指定元素5
      • 题目描述
      • 输入描述
      • 输出描述
      • 样例
      • 题解
    • 寻找指定元素6
      • 题目描述
      • 输入描述
      • 输出描述
      • 样例
      • 题解

概念

二分查找(Binary Search)算法,也叫折半查找算法。二分查找的思想非常简单,有点类似分治的思想。二分查找针对的是一个有序的数据集合,每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。

为了方便理解,我们以数组

1,3,5,7,11,13,17,19,23,29,31,37,41,43,53,59,在数组中查找37为例,制作了一张查找过程动图,其中low标示左下标,high标示右下标,mid标示中间值下标
在这里插入图片描述
可以看出二分查找在查找数字 37 时只需3次,而顺序查找 查找37时需要11次。

应用场景

二分搜索用于在一个单调或者局部单调有序数组中查找一个符合某些条件的值,时间复杂度为O(logN)

代码模板

int BinarySearch(int *a,int len,int key){int low = 0,high = len-1,mid;while(low<=high){mid = (low+high)/2;      //取中间位置if(a[mid] == key){return mid;          //查找成功并返回所在位置}else if( key < a[mid] ){   high = mid - 1;	     //从前半部分查找}else{low = mid + 1;	     //从后半部分查找}}
}

OJ练习

寻找指定元素1

题目描述

在一个严格递增序列A中寻找一个指定元素x,如果能找到,那么输出它的下标;如果不能找到,那么输出。

注:使用二分法实现。

输入描述

在这里插入图片描述

输出描述

如果能找到x,那么输出它的下标;否则输出-1。

样例

样例1

输入

5 3
1 2 3 5 8

输出

2

样例2

输入

5 6
1 2 3 5 8

输出

-1

题解

这题就是直接套模板

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
int A[N];int BinarySearch(int *a,int len,int key){int low = 0,high = len-1,mid;while(low<=high){mid = (low+high)/2;      //取中间位置if(a[mid] == key){return mid;          //查找成功并返回所在位置}else if( key < a[mid] ){   high = mid - 1;	     //从前半部分查找}else{low = mid + 1;	     //从后半部分查找}}return -1;
}int main(){int n,x;cin >> n >> x;for(int i = 0;i < n;i ++){cin >> A[i];}cout << BinarySearch(A,n,x);return 0;
}

寻找指定元素2

题目描述

在一个严格递减序列A中寻找一个指定元素x,如果能找到,那么输出它的下标;如果不能找到,那么输出-1。

注:使用二分法实现。

输入描述

在这里插入图片描述

输出描述

如果能找到x,那么输出它的下标;否则输出-1。

样例

样例1

输入

5 3
8 5 3 2 1

输出

2

样例2

输入

5 6
8 5 3 2 1

输出

-1

题解

这个就是在板子基础上,把大于号小于反过来就行了,递增变递减

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
int A[N];int BinarySearch(int *a,int len,int key){int low = 0,high = len-1,mid;while(low<=high){mid = (low+high)/2;      //取中间位置if(a[mid] == key){return mid;          //查找成功并返回所在位置}else if( key > a[mid] ){   high = mid - 1;	     //从前半部分查找}else{low = mid + 1;	     //从后半部分查找}}return -1;
}int main(){int n,x;cin >> n >> x;for(int i = 0;i < n;i ++){cin >> A[i];}cout << BinarySearch(A,n,x);return 0;
}

寻找指定元素3

题目描述

在一个递增序列A(可能存在重复元素)中寻找第一个大于等于x的序列下标。

注:使用二分法实现。

输入描述

在这里插入图片描述

输出描述

输出第一个大于等于x的序列下标。

样例

样例1

输入

5 5
1 4 5 5 7

输出

2

解释

序列中存在5,所以第一个大于等于5的元素就是5,对应的序列下标是2

样例2

输入

5 6
1 4 5 5 7

输出

4

解释

序列中不存在6,第一个大于等于6的元素是7,对应的序列下标是4

样例3

输入

5 8
1 4 5 5 7

输出

5

解释
序列中所有元素都小于8,因此第一个大于等于8的序列下标是5

题解

循环条件为low<high而非之前的low<=high,这是由问题本身决定的。在上一个问题中,需要当元素不存在时返回-1,这样当low>high时[low,high]这个区间就不存在了,可以此作为元素不存在的判定原则,因此low<=high满足时循环应当一致执行;但是如果想要返回第一个大于等于x的元素的位置,就不需要判断x本身是否存在,因为就算它不存在,返回的也是“假设它存在,它应该在的位置”,于是当low==high时,[low,high]刚好能夹出唯一的位置,就是需要的结果,因此只需要当low<high时让循环一直执行即可。

由于当low==high时while循环停止,因此最后的返回值既可以是low,也可以是high。

二分的初始区间应当能覆盖到所有可能返回的结果。首先,二分下界是0是显然的,但是二分上界是n-1还是n呢?考虑到要查询元素有可能比序列中的所有元素都要大,此时应当返回n(即假设它存在,它应该在的位置),因此二分上界是n,故二分的初始区间为[low,high]=[0,n]

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
int A[N];int BinarySearch(int *a,int len,int key){int low = 0,high = len;while(low<high){int mid = (low+high)/2;      if(a[mid] >= key){high = mid;         }else{   low = mid + 1;	     }}return low;
}int main(){int n,x;cin >> n >> x;for(int i = 0;i < n;i ++){cin >> A[i];}cout << BinarySearch(A,n,x);return 0;
}

寻找指定元素4

题目描述

在一个递增序列A(可能存在重复元素)中寻找第一个大于x的序列下标。

注:使用二分法实现。

输入描述

在这里插入图片描述

输出描述

输出第一个大于x的序列下标。

样例

样例1

输入

5 5
1 4 5 5 7

输出

4

解释

序列中存在5,所以第一个大于等于5的元素就是5,对应的序列下标是2

样例2

输入

5 6
1 4 5 5 7

输出

4

解释

序列中不存在6,第一个大于等于6的元素是7,对应的序列下标是4

样例3

输入

5 8
1 4 5 5 7

输出

5

解释
序列中所有元素都小于8,因此第一个大于等于8的序列下标是5

题解

此题和上题类似,只需要把等于号去掉

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
int A[N];int BinarySearch(int *a,int len,int key){int low = 0,high = len;while(low<high){int mid = (low+high)/2;      if(a[mid] > key){high = mid;         }else{   low = mid + 1;	     }}return low;
}int main(){int n,x;cin >> n >> x;for(int i = 0;i < n;i ++){cin >> A[i];}cout << BinarySearch(A,n,x);return 0;
}

寻找指定元素5

题目描述

在一个递增序列
A(可能存在重复元素)中寻找一个指定元素x,如果能找到,那么输出第一个x的下标;如果不能找到,那么输出-1。

注:使用二分法实现。

输入描述

在这里插入图片描述

输出描述

如果能找到x,那么输出第一个x的下标;否则输出-1。

样例

样例1

输入

5 5
1 5 5 5 7

输出

1

解释

序列中存在三个5,第一个5的序列下标是1

样例2

输入

5 6
1 5 5 5 7

输出

-1

解释

序列中不存在6,因此输出-1

题解

因为会有很多个重复数据,这里只要出现的第一个,那么我们可以改变二分时候查找到key的条件,我们现在不让他查找到就结束,如果查找到了,就让他往左缩短,因为要找的是第一个,如果找最后一个就往右缩短就行了。

需要注意的是,如果没有查找到key,我们需要额外一个bool类型变量,用来判断是否找到过,找到过那个位置就是high+1.没找到就返回-1,可以用三目运算符实现。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
bool isFound = false;
int A[N];int BinarySearch(int *a,int len,int key){int low = 0,high = len-1;while(low<=high){int mid = (low+high)/2;      if(a[mid] == key){high = mid-1;     isFound = true;    }else if( key < a[mid] ){   high = mid - 1;	    }else{low = mid + 1;	   }}return isFound==true?high+1:-1;
}int main(){int n,x;cin >> n >> x;for(int i = 0;i < n;i ++){cin >> A[i];}cout << BinarySearch(A,n,x);return 0;
}

寻找指定元素6

题目描述

在一个递增序列A(可能存在重复元素)中寻找一个指定元素x,如果能找到,那么输出最后一个x的下标;如果不能找到,那么输出-1。

注:使用二分法实现。

输入描述

在这里插入图片描述

输出描述

如果能找到x,那么输出最后一个x的下标;否则输出-1。

样例

样例1

输入

5 5
1 5 5 5 7

输出

3

解释

序列中存在三个5,最后一个5的序列下标是3

样例2

输入

5 6
1 5 5 5 7

输出

-1

解释

序列中不存在6,因此输出-1

题解

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
bool isFound = false;
int A[N];int BinarySearch(int *a,int len,int key){int low = 0,high = len-1;while(low<=high){int mid = (low+high)/2;      if(a[mid] == key){low = mid+1;     isFound = true;    }else if( key < a[mid] ){   high = mid - 1;	    }else{low = mid + 1;	   }}return isFound==true?low-1:-1;
}int main(){int n,x;cin >> n >> x;for(int i = 0;i < n;i ++){cin >> A[i];}cout << BinarySearch(A,n,x);return 0;
}

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

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

相关文章

报表生成器FastReport .Net用户指南:数据源与“Data“窗口

FastReport .Net是一款全功能的Windows Forms、ASP.NET和MVC报表分析解决方案&#xff0c;使用FastReport .NET可以创建独立于应用程序的.NET报表&#xff0c;同时FastReport .Net支持中文、英语等14种语言&#xff0c;可以让你的产品保证真正的国际性。 FastReport.NET官方版…

线性方程组计算

一、题型 1&#xff09;给一个线性方程组&#xff0c;问&#xff1a;唯一解&#xff1f;无解&#xff1f;无穷多解&#xff1f; 2&#xff09;在上面的基础上&#xff0c;给一个未知数λ&#xff0c;问&#xff1a;当λ为几时&#xff0c;方程组唯一解&#xff1f;无解&#…

镜像迁移脚本

在日常的服务部署开发中&#xff0c;我们有时需要迁移环境&#xff0c;将服务器上的私有镜像从一个服务器迁移到另一个服务器中。在以微服务为架构的项目中&#xff0c;我们的一个项目可能存在大量的镜像&#xff0c;对每一个镜像单独进行导出打包迁移即重复又麻烦&#xff0c;…

Springboot3+EasyExcel由浅入深

环境介绍 技术栈 springboot3easyexcel 软件 版本 IDEA IntelliJ IDEA 2022.2.1 JDK 17 Spring Boot 3 EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。 他能让你在不用考虑性能、内存的等因素的情况下&#xff0c;快速完成Excel的读、…

LabVIEW在动态力传感器校准技术的创新应用

简介 动态力传感器校准装置集成了冲击法原理和自动化控制&#xff0c;实现精准、高效的传感器校验。LabVIEW的图形化界面提供简便操作和实时数据分析&#xff0c;显著提高了校准过程的准确度和效率。 01 系统设计和功能 动态力传感器在工业生产中发挥着重要作用&#xff0c;…

Docker 安装部署

1、Docker 安装 ① 卸载docker&#xff0c;清空之前的docker文件 yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-selinux \docker-engine-selinux \docker-engine \docker-ce…

数据库创建表并插入数据练习题

一、创建表的要求 创建一个英雄表(hero) 主键 name nickname address groups email telphone 二、 操作步骤 1.登录MySQL [rootlocalhost ~]# systemctl start mysqld [rootlocalhost ~]# mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with…

【网络安全】【密码学】【北京航空航天大学】实验三、数论基础(下)【C语言实现】

实验三、数论基础&#xff08;下&#xff09; 一、实验内容 1、中国剩余定理&#xff08;Chinese Remainder Theorem&#xff09; &#xff08;1&#xff09;、算法原理 m1, m2, … mk 是一组两两互素的正整数&#xff0c;且 M m1 m2 … mk 为它们的乘积, 则如下的同余…

使用new pm写一个pass

范例来自LLVM Techniques, Tips, and Best Practices Clang and Middle-End Libraries llvm ir到ir是由一个个pass处理的&#xff0c;从一个ir到另一个ir会改变一些东西 书里面就是说想要给指针变量添加一个noalias属性 书里面使用插件的形式&#xff0c;但是不知道怎么我搞不…

MetaGPT前期准备与快速上手

大家好&#xff0c;MetaGPT 是基于大型语言模型&#xff08;LLMs&#xff09;的多智能体协作框架&#xff0c;GitHub star数量已经达到31.3k。 接下来我们聊一下快速上手 这里写目录标题 一、环境搭建1.python 环境2. MetaGpt 下载 二、MetaGPT配置1.调用 ChatGPT API 服务2.简…

手机扫一扫文档、证件表格就能打印,不用专门找扫描软件啦

现在各大品牌的手机扫一扫功能都可以满足扫描文档、扫描表格的功能&#xff0c;平常如果需要将纸质文件扫描成电子档&#xff0c;拿起手机就可以实现。文件签名后再扫描成PDF版本&#xff0c;相信大家都用得不少了。 今天就用华为手机的扫一扫给大家示范一下如何将文档、证件、…

设计模式—行为型模式之状态模式

设计模式—行为型模式之状态模式 状态&#xff08;State&#xff09;模式&#xff1a;对有状态的对象&#xff0c;把复杂的“判断逻辑”提取到不同的状态对象中&#xff0c;允许状态对象在其内部状态发生改变时改变其行为。 状态模式包含以下主要角色&#xff1a; 环境类&am…