CC53.【C++ Cont】二分查找的普通模版

news2025/5/13 19:47:26

目录

1.知识回顾

2.关键点

特点

三个模版

普通的模版(有局限)

以LeetCode上的一道题为例:704. 二分查找

分析

引入二段性:分两段,舍一段,操作另一段(这个是二分查找的本质!)

代码

提交结果

当然也可以使用随机数来分两段

普通模版总结


1.知识回顾

之前在C语言专栏中的文章提到了二分查找,可复习:

E7.【C语言】练习:在一个有序数组中查找具体的某个数字n(二分查找)

本文将提炼出一些关键点

2.关键点

特点

算法细节较多,一 一介绍:

之前讲过二分查找的前提: 数组有序时才能使用二分查找,其实并不是这样!,

当数组满足某特定规律时,也可以使用二分查找(这个后面会介绍)

三个模版

有以下二分查找的固定格式,做题只需要照葫芦画瓢,注意先理解再记忆

普通的模版(有局限)

以LeetCode上的一道题为例:704. 二分查找

https://leetcode.cn/problems/binary-search/description/

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1
示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

提示:

  1. 你可以假设 nums 中的所有元素是不重复的。
  2. n 将在 [1, 10000]之间。
  3. nums 的每个元素都将在 [-9999, 9999]之间。
分析

暴力解法直接从左向右或从右向左找,这里不写,讲讲暴力解法的缺陷:每次只能比较一个数,时间复杂度为O(N)

注意到题目条件"一个 n 个元素有序的(升序)整型数组 nums ",那么可以利用数组的单调性对暴力解法优化

以nums = [-1,0,3,5,9,12], target = 9为例说明,现查找到3,发现target>3且数组单增,那么3的左侧是不需要查找的,继续查找3的右侧

引入二段性:分两段,舍一段,操作另一段(这个是二分查找的本质!)

对于上述单增数组有许多分段方式:

1.二分

即近似分成二等分

2.三分

将数组近似分成三等分

然后任意选一个节点来分段,例如:

3.四分

将数组近似分成四等分......

......

当然也可以使用随机数来分段

其中二分的时间复杂度是最低的,时间复杂度为O(logN),当然某些情况下使用随机数来分段时间复杂度也比较低

算法:设数组是单调递增的,对它平分两段:

比较nums[mid]和num[target]的大小,

1.nums[mid]==num[target],结束循环,返回结果

2.nums[mid]<num[target],依据二段性:分两段,舍一段,操作另一段

,舍弃[left,mid]段,去[mid,right]段寻找,那么更新left

left=mid+1;//right不变

nums[mid]>num[target],返回结果,依据二段性:分两段,舍一段,操作另一段

,舍弃[mid,right]段,去[left,mid]段,那么更新right

right=mid-1;//left不变

3.更新mid(有多种方法,上面提过了)

只需要循环上面三步,变化寻找的区间,最终一定可以找到结果

结束循环的两个条件:

1.nums[mid]==num[target],直接返回结果

2.left>right,(注:left==right,分的段是一个"点",只有一个元素,但也需要判断是否等于target,仍然需要循环),没有找到target

那么循环的条件是:left\leqslantright

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

注:mid不要写成(left+right)/2!之前在L42.【LeetCode题解】四数之和(双指针思想) 从汇编角度分析报错原因文章提到过报错的原因,当数组过长时,加法可能导致溢出

防溢出的方法:(left+right)/2改为left+(right-left)/2或left+(right-left+1)/2

提交结果

同理三分法只需要将除数2改成3即可,四分法、五分法同理

mid=left+(right-left+1)/3;
当然也可以使用随机数来分两段
class Solution {
public:
    int search(vector<int>& nums, int target) 
    {
        srand((unsigned int)time(nullptr));
        int left=0;
        int right=nums.size()-1;
        int mid;
        while(left<=right)
        {
            mid=left+rand()%(right - left + 1);
            if (nums[mid]==target)
                return mid;
            if (nums[mid]>target)
                right=mid-1;
            if (nums[mid]<target)
                left=mid+1;   
        }
        return -1;
    }
};

注: 循环体中,如果最后更新mid将导致除0错误!

这样写是错误的:

class Solution {
public:
    int search(vector<int>& nums, int target) 
    {
        srand((unsigned int)time(nullptr));
        int left=0;
        int right=nums.size()-1;
        int mid=left+rand()%(right - left + 1);
        while(left<=right)
        {
           
            if (nums[mid]==target)
                return mid;
            if (nums[mid]>target)
                right=mid-1;
            if (nums[mid]<target)
                left=mid+1;
            mid=left+rand()%(right - left + 1);   
        }
        return -1;
    }
};

排查错误:

VS中进入调试模式

发生错误的地方是: mid = left + rand() % (right - left + 1),则mid=2+rand()%(1-2+1)=2+rand()%0,为除0错误,此时left仍然<=right,策略:先更新mid的值,这样进行if判断时能修改left和right的值,能及时退出循环,防止除0错误

提交结果:

普通模版总结

利用二段性填以下模版空缺的地方:

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

注意1.判断条件 2.mid防溢出方法 3.left和right的更新方式

其他两个模版见下一篇文章

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

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

相关文章

【优选算法 | 链表】链表操作技巧:常见算法

算法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;双指针滑动窗口二分查找前缀和位运算模拟 链表是一种灵活的数据结构&#xff0c;广泛用于需要频繁插入和删除的场景。掌握链表的常见操作技巧&#xff0c;如插入、删除、翻转和合并等&#xff0c;能帮助开发者更…

w~大模型~合集30

我自己的原文哦~ https://blog.51cto.com/whaosoft/13284996 #VideoMamba 视频理解因大量时空冗余和复杂时空依赖&#xff0c;同时克服两个问题难度巨大&#xff0c;CNN 和 Transformer 及 Uniformer 都难以胜任&#xff0c;Mamba 是个好思路&#xff0c;让我们看看本文是…

PBR材质-Unity/Blender/UE

目录 前言&#xff1a; 一、Unity&#xff1a; 二、Blender&#xff1a; 三、UE&#xff1a; 四、全家福&#xff1a; 五、后记&#xff1a; 前言&#xff1a; PBR流程作为表达物理效果的经典方式&#xff0c;很值得一学。纹理贴图使用的是上一期的Textures | cgbookcas…

websocketpp 安装及使用

介绍 WebSocket 是从 HTML5 开始支持的一种网页端和服务端保持长连接的消息推送机制。 传统的 web 程序都是属于 "一问一答" 的形式&#xff0c;即客户端给服务器发送了一个 HTTP 请求&#xff0c;服务器给客户端返回一个 HTTP 响应。这种情况下服务器是属于被动…

第8章-2 查询执行的基础

上一篇&#xff1a;《第8章-1 查询性能优化-优化数据访问》&#xff0c;接着来了解查询执行的过程&#xff0c;这个对sql执行有个更直观的了解。 查询执行的基础 当希望MySQL能够以更高的性能运行查询时&#xff0c;最好的办法就是弄清楚MySQL是如何优化和执行查询的。一旦理解…

java面试OOM汇总

在正式 Minor GC 前&#xff0c;JVM 会先检查新生代中对象&#xff0c;是比老年代中剩余空间大还是小。假如 Minor GC之后 Survivor 区放不下剩余对象&#xff0c;这些对象就要进入老年代 老年代剩余空间大于新生代中的对象大小&#xff0c;那就直接 Minor GC&#xff0c; GC 完…

react-diff-viewer 如何实现语法高亮

前言 react-diff-viewer 是一个很好的 diff 展示库&#xff0c;但是也有一些坑点和不完善的地方&#xff0c;本文旨在描述如何在这个库中实现自定义语法高亮。 Syntax highlighting is a bit tricky when combined with diff. Here, React Diff Viewer provides a simple rend…

自定义prometheus exporter实现监控阿里云RDS

# 自定义 Prometheus Exporter 实现多 RDS 数据采集## 背景1. Prometheus 官网提供的 MySQL Exporter 对于 MySQL 实例只能一个进程监控一个实例&#xff0c;数据库实例很多的情况下&#xff0c;不方便管理。 2. 内部有定制化监控需求&#xff0c;RDS 默认无法实现&#xff0c;…

【计算机网络】--tcp三次握手

文章目录 示意图&#xff1a;抓包结果&#xff1a;第一次握手&#xff08;Client → Server&#xff09;第二次握手&#xff08;Server → Client&#xff09;第三次握手&#xff08;Client → Server&#xff09;为什么是三次握手 不是两次或者四次 示意图&#xff1a; 抓包结…

UI-TARS: 基于视觉语言模型的多模式代理

GitHub&#xff1a;https://github.com/bytedance/UI-TARS 更多AI开源软件&#xff1a;发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI 基于视觉语言模型&#xff08;Vision-Language Model&#xff09;的 GUI 代理应用&#xff0c;允许用户通过自然语言控制电脑操…

Spark SQL 运行架构详解(专业解释+番茄炒蛋例子解读)

1. 整体架构概览 Spark SQL的运行过程可以想象成一个"SQL查询的加工流水线"&#xff0c;从原始SQL语句开始&#xff0c;经过多个阶段的处理和优化&#xff0c;最终变成分布式计算任务执行。主要流程如下&#xff1a; SQL Query → 解析 → 逻辑计划 → 优化 → 物理…

【计算机网络】网络IP层

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 上篇文章&#xff1a;传输层协议TCP 下篇文章&#xff1a;数据链路层 文章摘要&#xff1…

一天学会Maven

一、Maven简介和快速入门 1.1 Maven介绍 Maven 是一款为 Java 项目构建管理、依赖管理的工具&#xff08;软件&#xff09;&#xff0c;使用 Maven 可以自动化构建、测试、打包和发布项目&#xff0c;大大提高了开发效率和质量。 总结&#xff1a;Maven就是一个软件&#xf…

变量函数实战:高保真APP原型“发票页面”动态交互教程

变量函数是高保真交互原型设计中常见的高级交互功能&#xff0c;能够避免重复复制与手动修改页面元素和逻辑标注&#xff0c;让演示更有真实体验感。本文分享一个高保真APP交互原型页面的实操案例&#xff0c;结合原型设计工具中的变量函数与逻辑判断功能&#xff0c;手把手教你…

Spring Boot 3 + Undertow 服务器优化配置

优化背景 当你的application需要支持瞬时高并发的时候&#xff0c;tomcat已经不在是最优的选择&#xff0c;我们可以改为Undertow&#xff0c;并对其进行优化。 Undertow 是一个轻量级的、高性能的Java Web 服务器&#xff0c;由JBoss 开发并开源。它是基于非阻塞&#xff08;…

7系列 之 OSERDESE2

背景 《ug471_7Series_SelectIO.pdf》介绍了Xilinx 7 系列 SelectIO 的输入/输出特性及逻辑资源的相关内容。 第 1 章《SelectIO Resources》介绍了输出驱动器和输入接收器的电气特性&#xff0c;并通过大量实例解析了各类标准接口的实现。 第 2 章《SelectIO Logic Resource…

vue3+flask+sqlite前后端项目实战

基础环境安装 pycharm 下载地址&#xff1a; https://www.jetbrains.com/zh-cn/pycharm/download/?sectionwindows vscode 下载地址 https://code.visualstudio.com/docs/?dvwin64user python 下载地址 https://www.python.org/downloads/windows/ Node.js&#xff08;含npm…

Java 线程的堆栈跟踪信息

Java 线程的堆栈跟踪信息&#xff0c;展示了线程的当前状态和执行位置。以下是详细解释&#xff1a; 线程基本信息 "Thread-0" #16 prio5 os_prio0 cpu0.00ms elapsed16.29s tid0x00000243105a4130 nid0x5384 waiting on condition [0x0000007687ffe000]线程名称…

【计算机视觉】OpenCV实战项目:Long-Exposure:基于深度学习的长时间曝光合成技术

Long-Exposure&#xff1a;基于深度学习的长时间曝光合成技术 项目概述与技术背景项目核心功能技术原理 环境配置与安装硬件要求建议详细安装步骤可选组件安装 实战应用指南1. 基础使用&#xff1a;视频转长曝光2. 高级模式&#xff1a;自定义光轨合成3. 批量处理模式 技术实现…

传输层协议UDP和TCP

传输层协议UDP和TCP 1、UDP2、TCP2.1、TCP协议段格式2.2、确认应答(ACK)机制2.3、超时重传机制2.4、连接管理机制2.5、理解CLOSE_WAIT状态2.6、理解TIME_WAIT状态2.7、流量控制2.8、滑动窗口2.9、拥塞控制2.10、延迟应答2.11、捎带应答2.12、面向字节流2.13、粘包问题2.14、TCP…