二分查找----C/C++

news2024/10/6 8:33:35

目录

1. 二分查找的概念

 2. 整数的二分

2.1 二分的模版一

 2.2 二分的模版二

2.3. 案例剖析

2.4.整数二分总结

3. 浮点数的二分


1. 二分查找的概念

折半查找(BinarySearch)技术,又称为二分查找。它的前提是线性表中的记录
必须是关键码有序(通常从小到大有序),线性表必须采用顺序存储。

折半查找的基本思想是:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功; 若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。不断重复上述过程,直
到查找成功,或所有查找区域无记录,查找失败为止。

 2. 整数的二分

二分的本质:根据一定的条件或性质(一般是与答案之间的关系),可以将查找的区间分为两部分,然后对中间值mid进行判断,确定答案在mid的左侧还是右侧,以此来缩小查找的范围。

核心:保证答案在更新后的区间,当区间长度为1时我们就找到了答案。

二分查找是有两个模版的,根据这两个模版我们能够解决几乎全部的二分查找问题。

2.1 二分的模版一

int main()
{
	int L = 0;
	int R = length - 1; //length为数组的长度

	while (L < R)
	{
		int mid = L + R + 1 >> 1;
		if (check(mid)) //检查mid指向的元素在答案所分的两个区间的哪一侧
			L = mid;
		else
			R = mid - 1;
	}
	return 0;
}

 上图中,假设我们要确定的是绿色的点,在绿色区间的元素满足一定的条件,红色区间的元素也满足一定的条件(这两个区间的条件就是根据答案来确定的,后面有例题可以帮助大家理解),然后我们求出mid所在的区间,假设mid满足绿色区间的条件,那么答案(要确定的绿色的点)肯定在mid的右侧,并且mid也可能是答案,所以答案在 [ mid, R ],  更新方式为: L = mid;当mid不满足绿色区间的性质,那么mid就满足红色区间的性质,此时mid不可能是答案(要确定的绿色的点),所以答案就在 [ L, mid - 1 ] 的区间内,更新区间的方式:R = mid - 1。

为什么mid = L + R + 1 >> 1???,这是由我们更新区间的方式决定了的,我们假设 L = R - 1时,如果按照 mid = L + R >> 1 来算,那么 mid = L + L + 1 >> 2 = L,我们发现 mid = L,然后更新区间 L = mid,即是 L = L,区间并没有变化,就会陷入死循环。由此,当更新区间的方式为:L = mid,R = mid - 1 时计算 mid 的方式为:mid = L + R + 1 >> 1。

 2.2 二分的模版二


int main()
{
	int L = 0;
	int R = length - 1; //length为数组的长度

	while (L < R)
	{
		int mid = L + R >> 1;
		if (check(mid)) //检查mid指向的元素在答案所分的两个区间的哪一侧
			L = mid + 1;
		else
			R = mid;
	}
	return 0;
}

 上图中,假设我们要确定的是红色的边界点,我们求出mid,检查mid是否满足红色区间的条件,如果满足,则mid在红色区间,并且mid可能是答案,所以答案(要确定的红色点的下标) 在 [L, mid ]区间内,更新方式 R = mid,同理当mid不满足红色区间的条件,答案就在 [ mid + 1, R ] 的区间内,更新区间的方式为:L = mid + 1。

2.3. 案例剖析

原题链接:

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/

题目描述:

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

思路分析:

我们只需要进行两次二分查找,找到第一个target的下标和最后一个target位置的下标即可。

很据上面的基础知识,来分析此题:

(1):找第一个 target 的下标。非递减序列,第一个 target 将整个序列分为两部分,后面区间的元素满足 >= target 的条件,如果 mid 满足 >= target 的条件那么mid 就在后面的区间,并且mid可能是第一个target(条件是 >= target嘛),所以答案就在 [ L, mid ],更新方式为 R = mid,一旦我们确定了更新方式就知道了该用哪一个模板,显然就是模板二。然后就只需要套模板就行。

 (2):找最后一个 target 的下标。非递减序列,最后一个 target 将整个序列分为两部分,前面区间的元素满足 <= target 的条件,如果 mid 满足 <= target 的条件那么mid 就在前面的区间,并且mid可能是最后一个target(条件是 <= target嘛),所以答案就在 [ mid, R ],更新方式为 L = mid,一旦我们确定了更新方式就知道了该用哪一个模板,显然就是模板一。然后就只需要套模板就行。

 循环结束时 L = R 的最后返回 L 或则 R 都行,前提是 target 存在哈。

int* searchRange(int* nums, int numsSize, int target, int* returnSize){
    //放结果的数组
    int* array = (int*)malloc(sizeof(int) * 2);
    //返回的数组大小都是2
    *returnSize = 2;
    //如果是空的数组,返回两个-1
    if(numsSize == 0)
    {
        array[0] = -1;
        array[1] = -1;
        return array;
    }
    //找第一个target
    int L = 0, R = numsSize - 1;
    while(L < R)
    {
        //模板二
        int mid = L + R >> 1;
        if(nums[mid] >= target)
            R = mid;
        else
            L = mid + 1;
    }
    //如果找不到target,返回两个-1
    if(nums[L] != target)
    {
        array[0] = -1;
        array[1] = -1;
        return array;
    }
    //保存结果
    array[0] = L;
    //找第二个target
    L = 0;
    R = numsSize - 1;
    while(L < R)
    {
        //模版一
        int mid = L + R + 1 >> 1;
        if(nums[mid] <= target)
            L = mid;
        else
            R = mid - 1;
    }
    //保存结果
    array[1] = L;
    return array;
}

2.4.整数二分总结

 我们就是要根据一个条件(边界)分出两个区间来,本题也可以用其他条件,确定更新区间的方式。从而选择使用哪个模板解决问题。

核心:每次区间的更新都保证答案在新的区间中,当区间长度为1时,就能够的到答案

注意:二分一定有解,然而具体的题目不一定有解。

3. 浮点数的二分

因为浮点数不存在取整的问题,所以比较简单。

 那个 cin >> x 就是 scanf("%d", &x);

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

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

相关文章

mysql 分库分表、 分区(partition)、sharding-sphere 综合整理

引言&#xff1a; 一般情况下&#xff0c;如果单表数据量超过2000w的样子查询速度会很慢&#xff0c;因为内存无法存储其索引&#xff0c;使得之后的 SQL 查询会产生磁盘 IO&#xff0c;从而导致性能下降。解决方案&#xff1a;mysql 分区 、 分表处理 分库分表&#xff1a; 原…

【匠心打造】从0打造uniapp 可视化拖拽设计 c_o 第六篇

1、这个版本的变化是左侧增加了布局设计和包资源管理器 包资源管理器&#xff1a;eclipse的特称&#xff0c;左侧的项目管理。和hbuildx左侧类似 项目的整体设计结构如下: v1.0 普通模式&#xff1a;支持新建前端项目&#xff0c;拖拽&#xff0c;且生成前端项目&#xff08…

基于“遥感+”蓝碳储量估算、红树林信息提取实践技术应用与科研论文写作

目录 “遥感”助推蓝碳生态系统碳储量调查简介 第一章 高光谱遥感数据介绍及预处理 第二章 光谱特征分析与参量提取 第三章 高光谱遥感数据分类与制图 第四章 GEE数据处理介绍 第五章 碳储量时空变化与预测 大气温室气体浓度不断增加&#xff0c;导致气候变暖加剧&#x…

DFS的树上应用

目录 一、前言 二、树上的DFS 1、树的重心 2、树的重心例题 3、树的直径 4、树的直径例题 &#xff08;1&#xff09;做两次DFS 三、拓扑排序与DFS 1、用DFS解拓扑排序 2、欧拉路与DFS 3、用DFS输出一个欧拉回路 一、前言 本文主要讲了树上的DFS、树的重心、树的直…

538. 把二叉搜索树转换为累加树

538. 把二叉搜索树转换为累加树 难度中等 给出二叉 搜索 树的根节点&#xff0c;该树的节点值各不相同&#xff0c;请你将其转换为累加树&#xff08;Greater Sum Tree&#xff09;&#xff0c;使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 提醒一下&am…

关于浮点数使用的两个注意事项(C/C++)

目录 一.回顾浮点数的存储与读取 二.浮点数使用的第一个注意事项 三.浮点数使用的第二个注意事项 附&#xff1a; 观察内存中的FLT_MAX和FLT_MIN 一.回顾浮点数的存储与读取 http://t.csdn.cn/oVwte 浮点数的存入与读取流程总览&#xff1a; 二.浮点数使用的第一个注意事…

理解实现八大排序

目录 一、初步认识 二、直接插入排序 三、希尔排序 四、直接选择排序 五、堆排序 六、冒泡排序 七、快速排序 7.1 Hoare版本 7.2 挖坑法 7.3 前后指针法 7.4 非递归 7.5 优化方法 7.5.1 三数取中 7.5.2 小区间优化 八、归并排序 九、计数排序 一、初步认识 排…

Netty入门

二. Netty 入门 1. 概述 1.1 Netty 是什么&#xff1f; Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.Netty 是一个异步的、基于事件驱动的网络应用框架&…

简单开发网站+HTML标签

目录 一、学习路线 二、快速开发网站 1、简单demo 2、浏览器能识别的标签 ① 编码② Title ③ 标题 ④ div和span ⑤ 超链接 ⑥ 图片⑦ 列表 ⑧ 表格 ⑨ input系列 ⑩ 下拉框 ⑪ 多行文本 三、网络请求 四、案例 1、用户注册 2、用户登录 五、小结 1、学习标签的总…

网易互客CRM 微盟系统 管易系统 金蝶系统对接集成整体解决方案

前言&#xff1a;大部分的企业都可能只用一套系统组织架构复杂&#xff0c;业务流程繁琐&#xff0c;内部同时有CRM系统、OMS系统、ERP系统......且各个系统都需要独立登陆&#xff0c;造成IT部门数据监管困难&#xff01;如何在同一套中台系统上关联多管理系统呢&#xff1f;系…

【GD32F427开发板试用】-03-定时器1 的不算坑的坑和时钟设置

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;申小林 先说一下我使用定时器1 的时候吧&#xff0c;最开始我以为定时器1是挂在APB1上的&#xff0c;随意按照惯性思维&#xff0c;定时器的时…

vue3使用svg图标多种方式

方式1使用在线链接访问 在iconfont找到自己的项目的图标选择Symbol获取在线链接 2&#xff1a;在vue3项目中找到public的index.html进行script进行引入 打开浏览器看&#xff1a;这样就会自动注入到body下 在项目直接使用 //控制图标的大小<svg style"width: 10px; …

SAP ABAP 函数组组件缺失检查

有没有遇到如下几个场景 场景1 开发1&#xff0c;新建函数组1&#xff0c;创建函数1 开发2&#xff0c;在函数组1里&#xff0c;创建函数2 两者都传Q测试&#xff0c;开发2的先QAT完后发布生产&#xff0c;请求dump&#xff0c;找不到函数2 场景2 函数组1已传生产 开发1&#x…

编解码-性能优化-SIMD

文章目录前言MMXSSEAVX使用内置函数使用SSE/AVX命名规则SSE/AVX操作类别实战汇编使用优化前代码详解优化后代码详解引用文章#mermaid-svg-cWLDz5Rki1i4TgZ1 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#fff;}#mermaid-svg-cWLDz5Rki…

【JavaGuide面试总结】MySQL篇·中

【JavaGuide面试总结】MySQL篇中1.MySQL 的隔离级别是基于锁实现的吗&#xff1f;2.表级锁和行级锁了解吗&#xff1f;有什么区别&#xff1f;3.共享锁和排他锁简单说说4.意向锁有什么作用&#xff1f;5.InnoDB 有哪几类行锁&#xff1f;6.当前读和快照读有什么区别&#xff1f…

Go语言循环语句

Go语言循环语句 资料参考至菜鸟教程。 在不少实际问题中有许多具有规律性的重复操作&#xff0c;因此在程序中就需要重复执行某些语句。 以下为大多编程语言循环程序的流程图&#xff1a; Go语言提供了以下几种类型循环处理语句&#xff1a; 循环类型描述for循环重复执行语句块…

Base64

概述 Base64是一种基于64个字符的编码算法,经过Base64编码后的数据会比原始数据略长,为原来的4/3倍。经Base64编码后的字符串的字符数是以4为单位的整数倍。 编码表 即64个字符分别是: 字符个数A-Z26a-z260-910+1/1=用于补位 在电子邮件中,每行为76个字符,每行末需添加一…

【青训营】Go的依赖管理

Go的依赖管理 本节内容来自于&#xff1a;字节跳动青年训练营第五届 后端组 1.什么是依赖 实际开发的工程需要使用许多第三方库&#xff0c;这能够使得我们站在巨人的肩膀上&#xff0c;使用第三方库中封装好的函数&#xff0c;可以大大方便我们的程序开发&#xff0c;第三方…

Microsoft Teams上的编程教育

内容提示&#xff1a;Microsoft Teams上的 MakeCode Arcade 使用形式&#xff1a;Microsoft Teams中的 “作业” 服务 应用场景&#xff1a;编程教育 社团活动 个人经验&#xff1a;在校期间&#xff0c;每周学校都会有社团活动&#xff0c;学生们根据自己的兴趣爱好来选择社…

struct 结构体的内存对齐

&#x1f499;作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;一起学习C言 本文目录 在内存中观察 结构体内存对齐的规则&#xff1a; 为什么存在内存对齐&#xff1f; 编程中我们该如何设计结构体&#xff1f; 修改默认对齐数 相关笔试题 在内存中观察 首先…