C++刷题 -- 二分查找

news2024/11/18 13:59:16

C++刷题 – 二分查找

文章目录

  • C++刷题 -- 二分查找
  • 一、原理
  • 二、例题
    • 1.二分查找
    • 2.使用二分查找确定target左右边界
    • 3.x的平方根


一、原理

条件:数组为有序数组,数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的;

  • 第一种写法:
    在这里插入图片描述
    在这里插入图片描述
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
        while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};
  • 第二种写法:
    在这里插入图片描述
    在这里插入图片描述
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

二、例题

1.二分查找

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

2.使用二分查找确定target左右边界

https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/

  • 该题目的要点在于非递减数组(升序,但是有可能有重复数字)中寻找target的左右边界,target可能有多个重复值的情况;
  • 时间复杂度需要是O(log N),表明需要使用二分查找确定左右边界,不能采用遍历方法确定边界;
  • 先确定情况:
    • target不再nums区间内;
    • target在nums区间内,但是nums中没有target;
    • nums中有target;

使用二分查找确定边界的原理:
二分查找在没有查找到target的时候,target是在最终的(left, right)这个区间之内的,可以使用这个原理来分别找出左右边界;

  • 确定右边界
    在这里插入图片描述
    当nums[mid]的值小于等于target的时候,选择更新right_border,right_border需要跟着left更新,因为无论是否找到target,最终left一定会指向nums中大于target的数中最小的那个数,就是target的有边界(开区间);
  • 左边界同理;

特殊情况:

  • nums为{2, 2},target为3,最终左右边界输出值为(-2, 2),之间的差值大于1,应该输出左右边界,但是target却不在nums中;
    解决方案:直接在最外面加一个判断target是否属于nums区间的条件;
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> res;
        
        int tar_l = leftBorder(nums, target);
        int tar_r = rightBorder(nums, target);
        cout << tar_l << "   " << tar_r << endl;

        if(nums.empty() || (target < nums[0] || target > nums[nums.size() - 1]))
        {
            //target不在nums范围
            res.push_back(-1);
            res.push_back(-1);
        }
        else if(tar_r - tar_l > 1)
        {
            //target存在于nums中
            res.push_back(tar_l + 1);
            res.push_back(tar_r - 1);
        }
        else
        {
            //target不存在于nums中
            res.push_back(-1);
            res.push_back(-1);
        }

        return res;
    }

    //寻找右边界 -- target右边的一个位置
    int rightBorder(vector<int>& nums, int target)
    {
        int right_border = -2;
        int left = 0, right = nums.size() - 1;
        //进行二分查找
        while(left <= right)
        {
            int mid = left + ((right - left) / 2);
            if(nums[mid] > target)//不断缩小右边界
            {
                right = mid - 1;
            }
            else
            {
                //缩小左边界
                //且当找到target时,left继续向右,目的是找到最右边target的位置
                left = mid + 1;
                right_border = left;
                //left最终指向的会是nums中大于target的最小数
            }
        } 
        return right_border;
    }
    
    //寻找左边界
    int leftBorder(vector<int>& nums, int target)
    {
        int left_border = -2;
        int left = 0, right = nums.size() - 1;
        //进行二分查找
        while(left <= right)
        {
            int mid = left + ((right - left) / 2);
            if(nums[mid] < target)//不断缩小左边界
            {
                left = mid + 1;
            }
            else
            {
                //缩小右边界
                //且当找到target时,right继续向右,目的是找到最左边target的位置
                right = mid - 1;
                left_border = right;
                //right最终指向的会是nums中小于target的最大数
            }
        } 
        return left_border;
    }

};

3.x的平方根

https://leetcode.cn/problems/sqrtx/submissions/483798269/

从题目的要求和示例我们可以看出,这其实是一个查找整数的问题,并且这个整数是有范围的。

  • 如果这个整数的平方 恰好等于 输入整数,那么我们就找到了这个整数;
  • 如果这个整数的平方 严格大于 输入整数,那么这个整数肯定不是我们要找的那个数;
  • 如果这个整数的平方 严格小于 输入整数,那么这个整数 可能 是我们要找的那个数(重点理解这句话)。

因此我们可以使用「二分查找」来查找这个整数,不断缩小范围去猜。
方法一:

  • 猜的数平方以后大了就往小了猜;
  • 猜的数平方以后恰恰好等于输入的数就找到了;
  • 猜的数平方以后小了,可能猜的数就是,也可能不是。
class Solution {
public:
    int mySqrt(int x) {
        int min = 0, max = x;
        int res = 0;
        
        while(min <= max)
        {
            int mid = min + (max - min) / 2;
            if((long long)mid * mid <= x)  // 防止乘法溢出
            {
            	// 目标结果的平方小于等于x,寻找出的就是范围内最大的满足平方<=x的数
                min = mid + 1;
                res = mid;
            }
            else
            {
                max = mid - 1;
            }
        }
        return res;
    }
};

方法二:

  • 使用二分查找寻找边界,目标数其实就是左边界
class Solution {
public:
    int mySqrt(int x) {
        int min = 0, max = x;
        int res = 0;
        //寻找左边界
        while(min <= max)
        {
            int mid = min + ((max - min) / 2);
            if((long long)mid * mid < x)
            {
                min = mid + 1;
            }
            else if((long long)mid * mid > x)
            {
                max = mid - 1;
                res = max;
            }
            else
            {
                return mid;
            }
        }
        return res;
    }
};

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

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

相关文章

网工内推 | 字节原厂,正式编,网络工程师,最高30K*15薪

01 字节跳动 招聘岗位&#xff1a;网络虚拟化高级研发工程师 职责描述&#xff1a; 1、负责字节跳动虚拟网络产品的研发&#xff0c;包括但不局限于网络VPC、NAT、LB负载均衡等&#xff1b; 2、负责字节跳动网络基础平台的研发&#xff0c;包括但不局限于网络控制面系统、容器…

LeetCode算法心得——爬楼梯(记忆化搜索)

大家好&#xff0c;我是晴天学长&#xff0c;第二个记忆化搜索练习&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1&#xff09;爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或…

解决Zotero不显示标签的问题

目录 问题描述 解决办法&#xff1a; 问题描述 Zotero是一款学习助手&#xff0c;可以帮助我们梳理文献&#xff0c;方便我们整理。 最近电脑从windows换到mac&#xff0c;重新安装了Zotero&#xff0c;发现之前的一直设置都没有了。比如设置好的标签信息不显示了。如下图: …

Deep Learning for Monocular Depth Estimation: A Review.基于深度学习的深度估计

传统的深度估计方法通常是使用双目相机&#xff0c;计算两个2D图像的视差&#xff0c;然后通过立体匹配和三角剖分得到深度图。然而&#xff0c;双目深度估计方法至少需要两个固定的摄像机&#xff0c;当场景的纹理较少或者没有纹理的时候&#xff0c;很难从图像中捕捉足够的特…

庖丁解牛:NIO核心概念与机制详解 07 _ 字符集

文章目录 Pre概述编码/解码处理文本的正确方式示例程序Code Pre 庖丁解牛&#xff1a;NIO核心概念与机制详解 01 庖丁解牛&#xff1a;NIO核心概念与机制详解 02 _ 缓冲区的细节实现 庖丁解牛&#xff1a;NIO核心概念与机制详解 03 _ 缓冲区分配、包装和分片 庖丁解牛&…

JS--localStorage设置过期时间的方案(有示例)

原文网址&#xff1a;JS--localStorage设置过期时间的方案(有示例)_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍如何使用localStorage设置数据的过期时间。 问题描述 localStorage是不支持设置过期时间的&#xff0c;cookie虽然支持设置过期时间但它存的数据量很小。所…

CMap数据库筛选化学药物

数据库clue.io 文献链接&#xff1a;连接图谱&#xff1a;使用基因表达特征连接小分子、基因和疾病 |科学 (science.org) 基本模式&#xff1a;利用CMap将差异基因列表与数据库参考数据集比对&#xff1b;根据差异表达基因在参考基因表达谱富集情况得到一个相关性分数&#…

Java实现windows系统截图

Java提供了一种方便的方式来截取Windows系统的截图。这个过程通常需要使用Java的Robot类来模拟用户的鼠标和键盘输入操作。下面将介绍如何使用Java实现Windows系统截图。 步骤1&#xff1a;导入Robot和AWT包 Java提供了一个Robot类&#xff0c;它可以模拟用户的键盘和鼠标操作…

欧科云链研究院:从香港SFC最新文件看链上交易合规必备之选

出品&#xff5c;欧科云链研究院 作者&#xff5c;Hedy Bi 近日&#xff0c;香港证监会在其官网发布“致持牌法团、获证监会发牌的虚拟资产服务提供者及有联系实体的通函 - 打击洗钱&#xff0f;恐怖分子资金筹集经更新的《打击洗钱&#xff0f;恐怖分子资金筹集的自我评估查…

2023年【T电梯修理】考试题及T电梯修理考试报名

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 T电梯修理考试题是安全生产模拟考试一点通总题库中生成的一套T电梯修理考试报名&#xff0c;安全生产模拟考试一点通上T电梯修理作业手机同步练习。2023年【T电梯修理】考试题及T电梯修理考试报名 1、【多选题】GB/T1…

matlab设置背景颜色

matlab默认的背景颜色是纯白RGB(255,255,255)&#xff0c;纯白太刺眼&#xff0c;看久了&#xff0c;眼睛会酸胀、疼痛&#xff0c;将其改成豆沙绿RGB(205,123,90)&#xff0c;或者给出浅绿色RGB(128,255,255), 颜色就会柔和很多&#xff0c;眼睛感觉更舒适。     下面介绍在…

风电场数字孪生-升压站BIM三维模型-obj格式

简介&#xff1a; 风电场中的升压站三维模型&#xff0c;obj格式&#xff0c;采用BIM技术建模&#xff0c;可应用于风电场三维数字孪生领域&#xff0c;用于对升压站进行漫游浏览&#xff1b;三维可视化场景应用&#xff1b;风电场三维设计模型。 下载地址 风电场数字孪生-升…

SMART PLC累计流量功能块(梯形积分法+浮点数累加精度控制)

S7-200SMART PLC数值积分器相关知识请参考下面文章链接: SMART PLC数值积分器功能块(矩形+梯形积分法完整源代码)-CSDN博客文章浏览阅读153次。PLC的数值积分器算法也可以参考下面文章链接:PLC算法系列之数值积分器(Integrator)-CSDN博客数值积分和微分在工程上的重要意义不…

C# - Opencv应用(2) 之矩阵Mat使用[矩阵创建、图像显示、像素读取与赋值]

C# - Opencv应用&#xff08;2&#xff09; 之矩阵Mat使用[矩阵创建、图像显示、像素读取与赋值] 矩阵创建图像显示与保存像素读取与赋值新建sample02项目&#xff0c;配置opencv4相关包&#xff0c;新建.cs进行测试 1.矩阵创建 //创建空白矩阵 var dst new Mat()//创建并赋…

【Java 进阶篇】JavaScript JSON 语法入门:轻松理解数据的序列化和反序列化

嗨&#xff0c;亲爱的小白们&#xff01;欢迎来到这篇关于 JavaScript 中 JSON&#xff08;JavaScript Object Notation&#xff09;语法的入门指南。JSON 是一种轻量级的数据交换格式&#xff0c;广泛应用于前端开发中。通过这篇博客&#xff0c;我将带你深入了解 JSON 的语法…

VSCode任务tasks.json中的问题匹配器problemMatcher的问题匹配模式ProblemPattern详解

☞ ░ 前往老猿Python博客 ░ https://blog.csdn.net/LaoYuanPython 一、简介 在 VS Code 中&#xff0c;tasks.json 文件中的 problemMatcher 字段用于定义如何解析任务输出中的问题&#xff08;错误、警告等&#xff09;。 problemMatcher有三种配置方式&#xff0c;具体可…

Hibernate 一级缓存,二级缓存,查询缓存

概念&#xff1a; 1.什么是缓存呢&#xff1f; 缓存&#xff1a;是计算机领域的概念&#xff0c;它介于应用程序和永久性数据存储源之间。 缓存&#xff1a;一般人的理解是在内存中的一块空间&#xff0c;可以将二级缓存配置到硬盘。用白话来说&#xff0c;就是一个存储数据的…

Spring Cloud Alibaba Sentinel 简单使用

Sentinel Sentinel 主要功能Sentinel 作用常见的流量控制算法计数器算法漏桶算法 令牌桶算法Sentinel 流量控制Sentinel 熔断Sentinel 基本使用添加依赖定义资源定义限流规则定义熔断规则如何判断熔断还是限流自定义 Sentinel 异常局部自定义异常全局自定义异常系统自定义异常…

战备器材管理系统-部队物资仓库管理系统

一、项目背景 传统的战备物资管理&#xff0c;一般依赖于一个非自动化的、以纸张文件为基础的系统来记录、追踪进出的货物&#xff0c;完全由人工实施仓库内部的管理&#xff0c;因此仓库管理的效率极其低下。对此&#xff0c;我们运用无线射频技术(RFID)的仓库智能管理系统&am…

RabbitMQ 基础操作

概念 从计算机术语层面来说&#xff0c;RabbitMQ 模型更像是一种交换机模型。 Queue 队列 Queue&#xff1a;队列&#xff0c;是RabbitMQ 的内部对象&#xff0c;用于存储消息。 RabbitMQ 中消息只能存储在队列中&#xff0c;这一点和Kafka相反。Kafka将消息存储在topic&am…