【算法】C++中的二分查找

news2024/10/20 20:35:32

📢博客主页:https://blog.csdn.net/2301_779549673
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨

在这里插入图片描述

在这里插入图片描述

文章目录

  • 📢前言
  • 🏳️‍🌈二分查找的实现方式
  • 🏳️‍🌈1. 朴素的二分模板
  • 🏳️‍🌈2. 查找左端点的二分模板
  • 🏳️‍🌈3. 查找右端点的二分模板
  • 👥总结


📢前言

请添加图片描述
二分查找,也被称为折半查找,是一种在有序数组中高效查找目标元素的算法。它的基本思想是将待查找的区间不断地折半,通过比较中间元素与目标元素的大小关系,逐步缩小查找范围,直到找到目标元素或者确定目标元素不存在于数组中。

二分查找的优点在于其查找速度较快。在有序数组中,对于长度为 n 的数组,二分查找的时间复杂度为 O (log n)。相比之下,线性查找的时间复杂度为 O (n)。例如,在一个包含 1024 个元素的有序数组中,线性查找最坏情况下可能需要进行 1024 次比较,而二分查找最多只需要进行 10 次比较(log₂1024 = 10)。


🏳️‍🌈二分查找的实现方式

在二分查找中,二段性是一个非常重要的概念。

二段性指的是对于一个有序数组,存在一种性质,使得数组可以被划分为两个区间,满足在其中一个区间中性质成立,在另一个区间中性质不成立。

例如,对于一个升序排列的整数数组,要查找某个特定的整数 target。如果当前数组中的某个元素大于等于 target,那么可以认为这个元素以及它右边的部分处于一个区间,这个区间中的元素都大于等于 target;而这个元素左边的部分处于另一个区间,这个区间中的元素都小于 target。这就体现了二段性。

根据数学演算,每次取最中值的二分查找算法是时间复杂度最均匀和最好的,这在算法导论中有证明,但是太复杂了,就不在这说了

1. 确定查找方向

  • 在二分查找过程中,通过判断当前中间元素与目标元素的大小关系,可以确定目标元素位于哪一个区间。
  • 如果中间元素小于目标元素,说明目标元素在中间元素右侧的区间;如果中间元素大于目标元素,说明目标元素在中间元素左侧的区间。

2. 缩小查找范围

  • 利用二段性,可以不断地将查找范围缩小一半。每次判断都能排除掉一半的区间,从而大大提高查找效率。
  • 例如,在一个有 100 个元素的有序数组中,使用二分查找最多只需要进行 7 次比较就可以找到目标元素,而如果采用顺序查找可能需要最多 100 次比较。

🏳️‍🌈1. 朴素的二分模板

在这里插入图片描述
朴素的二分查找模板的查找效率其实可以说是最高的,因为它一旦遇到准确的值就会直接退出,但是这也为其添加了局限性,如果数组不存在指定值,或者需要查找的是一个区间的左值 or 右值,那么就很难实现

在这里插入图片描述
以题为例 链接: 704. 二分查找
在这里插入图片描述

这道题就可以用朴素二分查找来做,

  1. 设置循环条件:left <= right
  2. mid = left + ((right - left) >> 1) : 查中间值(偶数时取左值),并设置防溢出
  3. 设置 大于 小于 等于 的情况
  4. 一旦 等于 返回值
  5. 循环结束未找到,返回 -1
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) left = mid + 1;
            else if(nums[mid] > target) right = mid -1;
            else return mid;
        }
        return -1;
    }
};

朴素二分模板总结

在这里插入图片描述

🏳️‍🌈2. 查找左端点的二分模板

在这里插入图片描述
查找最左值时可以参考上图,我们需要找到一个值使其左边都是小于要查找的值的,右边包括其本身都是要大于等于要查找的值的,因此我们假设 [0, left) [right, end]为两个分区,那么我们就可以认为

1. 退出循环的值为 left < right

再然后我们因为要查找的值 如果 t >= nums[right] 那么代表他必然属于右边这个区间,因此,我们在设置 right 更新时,不能使其 right = mid - 1,而是

2. if(… >= …) right = mid

同理我们推导left,left 的最终所处位置其实应该和 right 一样,因为它往左的所有元素都是小于 t 的,因而 left 更新时

3. else left = mid + 1

最后我们需要确保循环不会一直下去,这就我们需要确保,当 left + 1 == right 时我们所查找的 mid 值。如果查右边,那么将一直进行 if(… >= …) right = mid 导致陷入死循环,所以

4. mid = left + ((right - left) >> 1))

最左值二分模板总结
在这里插入图片描述

🏳️‍🌈3. 查找右端点的二分模板

在这里插入图片描述

最右值其实和最左值的理解差不多,就是有 等于 的时候,left 不用超过mid,right 变成 mid - 1。

还有一个重要的点是,mid 的确定,因为 当 left + 1 == right 时我们所查找的 mid 值 为左值时,就会一直 if(… <= …) left = mid 陷入死循环,所以 mid = left + ((right - left + 1) >> 1))

最右值二分模板总结

在这里插入图片描述

以题为例 链接: 34. 在排序数组中查找元素的第一个和最后一个位置 - 同时解决左端点右端点问题
在这里插入图片描述
具体流程完完全全就是左右端点的模板,就不逐条解释了

vector<int> searchRange(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        vector<int> ret{-1, -1};
        // 防止传入vector为空
        if (nums.empty())
            return ret;

        // 找左端点
        while (left < right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid] < target)
                left = mid + 1;
            else
                right = mid;
        }
        if (nums[right] == target)
            ret[0] = right;
        right = nums.size() - 1;

        // 找右端点
        while (left < right) {
            int mid = left + ((right - left + 1) >> 1);
            if (nums[mid] > target)
                right = mid - 1;
            else
                left = mid;
        }
        if (nums[left] == target)
            ret[1] = left;
        return ret;
    }

👥总结


本篇博文对 【算法】C++中的二分查找 做了一个较为详细的介绍,不知道对你有没有帮助呢

觉得博主写得还不错的三连支持下吧!会继续努力的~

请添加图片描述

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

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

相关文章

wifi、热点密码破解 - python

乐子脚本&#xff0c;有点小慢&#xff0c;试过多线程&#xff0c;系统 wifi 连接太慢了&#xff0c;需要时间确认&#xff0c;多线程的话系统根本反应不过来。 也就可以试试破解别人的热点&#xff0c;一般都是 123456 这样的傻鸟口令 # coding:utf-8 import pywifi from pyw…

初识git · 基本操作

目录 前言&#xff1a; 基本操作 检查是否存在git 初始化仓库 认识三个区域 添加文件 查看.git文件 修改文件 版本回退 撤销操作 删除文件 我的博客即将同步至腾讯云开发者社区&#xff0c;邀请大家一同入驻&#xff1a;https://cloud.tencent.com/developer/suppor…

Qt-多线程

1. Qt 多线程概述 Qt 默认只有一个主线程&#xff0c;该线程既要处理窗口移动&#xff0c;又要处理各种运算。 当要处理的运算比较复杂时&#xff0c;窗口就无法移动&#xff0c;所以在处理程序时在很多情况下都需要使用多线程来完成。 示例&#xff1a;移动窗口和复杂循环 …

八股面试2(自用)

mysql存储引擎 存储引擎&#xff1a;定义数据的存储方式&#xff0c;以及数据读取的实现逻辑 在以前数据库5.5默认MyISAM引擎&#xff0c;之后默认InnoDB引擎 MyISAM引擎的数据和索引是分开存储的&#xff0c;InnoDb将索引和文件存储在同一个文件。 MyISAM不支持事务&#…

SPOOLing技术详解,结合实际场景让你了解什么是假脱机技术。

SPOOLing技术 ​ 在手工操作阶段&#xff0c;主机直接从I/O设备获取数据&#xff0c;但是由于设备速度很慢&#xff0c;主机速度很快。人机速度矛盾明显&#xff0c;主机需要浪费很多时间来等待设备。 什么是脱机技术&#xff0c;脱机技术可以解决什么问题&#xff1f; 所谓脱…

大数据测试:Charles修改响应数据

上一篇大数据测试&#xff1a;Fiddler修改响应数据-CSDN博客 &#xff0c;有同学反馈有没有Charles的方式修改响应数据&#xff0c;本篇就是Charles修改数据操作步骤&#xff0c;相比较fiddler&#xff0c;Charles相对简单&#xff0c;便捷&#xff0c;我很喜欢 1、背景&…

【笔记】【YOLOv10图像识别】自动识别图片、视频、摄像头、电脑桌面中的花朵学习踩坑

&#xff08;一&#xff09;启动 创建环境python3.9 打开此环境终端 &#xff08;后面的语句操作几乎都在这个终端执行&#xff09; 输入up主提供的语句&#xff1a;pip install -r requirements.txt 1.下载pytorch网络连接超时 pytorch网址&#xff1a; Start Locally | P…

java -jar 命令自动重启 Java 项目

一、java -jar 方式运行项目 重启Java项目通常意味着你需要先停止当前运行的Java进程&#xff0c;然后再次启动它。下面是在CentOS上执行这些步骤的一种常见方法&#xff1a; 停止Java进程 找到Java进程的PID&#xff1a; 使用ps命令配合grep来查找运行中的Java进程的PID&#…

【Java SE 】封装 的特性 和 static 详解

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 1. 封装的概念 1.1 一个例子 2. 访问权限控制符 3. 包的概念 3.1 import 导入 3.2 常见的包 4. static 静态成员 4.1 static 使用情况 4.2 static 修…

> Invalid revision: 3.22.1-g37088a8-dirty

Android项目使用cmake 3.22.1&#xff0c;编译时报错&#xff1a; > Invalid revision: 3.22.1-g37088a8-dirty解决方法一&#xff1a; 升级Gradle版本和AGP的版本&#xff1b; 建议使用AS推荐的版本&#xff1a; 目前可运行的版本配置&#xff1a; AS&#xff1a;Jel…

champ模型部署指南

一、介绍 champ是由阿里巴巴、复旦大学和南京大学的研究人员共同提出的一种基于3D的将人物图片转换为视频动画的模型&#xff0c;该方法结合了3D参数化模型(特别是SMPL模型)和潜在扩散模型&#xff0c;能够精确地捕捉和再现人体的3D形状和动态&#xff0c;同时保持动画的时间一…

读书读到NOBEL

最近在读陈逸鹤的《程序员的自我修养》这本书&#xff0c;里面有这么一段话&#xff1a; “远古时代的人们只能创造出用于猎捕的长矛&#xff0c;而今天借助来自各行各业人 们的智慧&#xff0c;我们可以制造出高铁、大型飞机&#xff0c;并探索宇宙。但要更进一步解决人类所面…

2024_E_100_连续字母长度

连续字母长度 题目描述 给定一个字符串&#xff0c;只包含大写字母&#xff0c;求在包含同一字母的子串中&#xff0c;长度第 k 长的子串的长度&#xff0c;相同字母只取最长的那个子串。 输入描述 第一行有一个子串(1<长度<100)&#xff0c;只包含大写字母。 第二行为…

GPT-4o canvas不是对cursor的颠覆,而是人与AI交互的新探索

谈一下Openai新发布的canvas。 关于这个产品的介绍不多说了&#xff0c;网上已经有很多&#xff0c;主要谈下我对它以及相似竞品的比较&#xff0c;以及我的一些看法。 1、vs Claude Artifacts&#xff1a;是chatbot编程方面直接竞品&#xff0c;不过现阶段还是有很大的区别。…

二百六十八、Kettle——同步ClickHouse清洗数据到Hive的DWD层静态分区表中(每天一次)

一、目的 实时数仓用的是ClickHouse&#xff0c;为了避免Hive还要清洗数据&#xff0c;因此就直接把ClickHouse中清洗数据同步到Hive中就行 二、所需工具 ClickHouse&#xff1a;clickhouse-client-21.9.5.16 Kettle&#xff1a;kettle9.2 Hadoop&#xff1a;hadoop-3.1.3…

TH-OCR:强大的光学字符识别工具与车牌识别应用

在当今数字化的时代&#xff0c;高效准确地识别文本和图像中的字符变得至关重要。TH-OCR&#xff08;清华 OCR&#xff09;作为一款优秀的光学字符识别软件&#xff0c;以其卓越的性能和广泛的应用场景&#xff0c;受到了众多用户的青睐。其中&#xff0c;车牌识别功能更是在交…

嵌入式入门学习——6Protues点亮数码管,认识位码和段码,分辨共阴还是共阳(数字时钟第一步)

0 系列文章入口 嵌入式入门学习——0快速入门&#xff0c;Let‘s Do It&#xff01; 首先新建基于Arduino UNO的protues工程&#xff0c;见本系列第3篇文章 1 点“P”按钮找器件 2 输入“seg”或“digit”查找数码管器件 3 找到我们想要的6位7段数码管 4如图A、B…DP都是段码…

一、go入门

go入门 Go历史1.1 诞生时间1.2 里程碑1.3 团队核心人员 2. 为什么使用Go3. 安装Go5. 入门案例6. 开发工具 Go历史 1.1 诞生时间 Go 语言起源 2007 年&#xff0c;并于 2009 年正式对外发布。它从 2009 年 9 月 21 日开始作为谷歌公司 20% 兼职项目&#xff0c;即相关员工利用…

MATLAB小波变换图像融合系统

二、应用背景及意义 本课题利用小波变换进行图像的融合&#xff0c;然后对融合的结果进行图像质量的评价。所谓小波变换图像融合就是对多个的信息目标进行一系列的图像提取和合成&#xff0c;进而可以获得对同一个信息目标的更为精确、全面、可靠的高低频图像信息描述。并且也…

Vue2项目-二进制流预览

一、docx文档 软件&#xff1a;docx-preview&#xff1b; 版本&#xff1a;"^0.1.20"&#xff1b; 1、安装docx-preview npm i docx-preview0.1.20 2、组件配置 <template><div ref"wordContainer"></div> </template><s…