【leetcode】二分查找专题

文章目录

  • 1.基本的二分查找
  • 2.使用二分 查找左右端点
    • 2.1 左右端点
    • 2.2 二分模板
  • 3.搜索插入位置
  • 4.x的平方根
  • 5.山脉数组的顶峰
  • 6.寻找峰值
  • 7.寻找旋转排序数组中的最小值

在这里插入图片描述

对于二分查找,相信大家都再熟悉不过了。一旦数据是有序的,我们大概率会想到二分,但是有时候数据不是有序时,也可以使用二分。下面我们就来写几道关于二分的题目。

1.基本的二分查找

在这里插入图片描述

题目链接

二分的精髓就在于它一次就可以决定一半数据的归属,该题就是一个最简单的二分题。

在这里插入图片描述

由于left和right相遇时可能就是target,所以循环的条件应该是left <= right

当left与right错开时,就说明没有target这个元素,返回-1

如果数据太多,left和right较大时,我们计算mid时,left + right可能会溢出;
所以我们可以这样 mid = left + (right - left) / 2 ;

    int search(vector<int>& nums, int target) {
        int left = 0;
        int 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.使用二分 查找左右端点

2.1 左右端点

在这里插入图片描述
题目链接

对于该题目,就是在朴素二分的基础上,让你在区间中选择两个位置,该位置标记了target元素的开始与结束。

但是我们这一题需要在朴素二分的基础上进行变化。

在这里插入图片描述


在这里插入图片描述

    vector<int> searchRange(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size()-1;
        if(nums.size() == 0)
            return {-1,-1};

        int begin = -1;
        int end = -1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            //小于target,去掉[left,mid]区间
            if(nums[mid] < target)
                left = mid + 1;
            //大于等于target,去掉(mid,right]
            else
                right = mid;
        }
        if(nums[left] != target)
            return {-1,-1};
        
        begin = left;

        left = 0;
        right = nums.size() - 1;

        while(left < right)
        {
            int mid = left + (right - left + 1) / 2;
            //小于等于target,去掉[left,mid)区间
            if(nums[mid] <= target)
                left = mid;
            //大于target,去掉[mid,right]区间
            else
                right = mid - 1;
        }   
        if(nums[left] != target)
            return {-1,-1};
        end = left;
        return {begin,end};
    }

在这里插入图片描述

2.2 二分模板

求左端点

        while (left < right)
        {
            int mid = left + (right - left) / 2;
            //小于target,去掉[left,mid]区间
            if (...)
                left = mid + 1;
            //大于等于target,去掉(mid,right]
            else
                right = mid;
        }

求右端点

        while (left < right)
        {
            int mid = left + (right - left + 1) / 2;
            //小于等于target,去掉[left,mid)区间
            if ()
                left = mid;
            //大于target,去掉[mid,right]区间
            else
                right = mid - 1;
        }

3.搜索插入位置

在这里插入图片描述

由于该题目也具有二段性,因此也使用二分。、

  • 当left与right相遇时
    • 如果 nums[left] < target,则表明数组中没有target元素,则target元素应插入到left后面
    • 如果 nums[left] > target,则表明数组中没有target元素,left位置就是target要插入的位置
    • 如果 nums[left] == target,则表明数组中有target元素,left位置就是target的下标
    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;

        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] < target)
                left = mid + 1;
            else
                right = mid;
        }

        if(nums[left] < target)
            return left + 1;
        else 
            return left;
    }

4.x的平方根

在这里插入图片描述
题目链接

解法一:暴力查找

使用 i 依次遍历1-x的数,直到 i*i >= x时,就可以出现结果。为了防止溢出,应使用long long

    int mySqrt(int x) {
        for(long long i=1; i<=x; i++)
        {
            if(i* i == x)
                return i;
            else if(i *i > x)
                return i-1;
        }
        return 0;
    }

解法二:二分查找

对于1-x之间的数,它平方的结果具有二段性,要么> x,要么 <= x,因此可以使用二分优化暴力解法。

    int mySqrt(int x) {
        if(x == 0)
            return 0;
        int left = 1;
        int right = x;
        while(left < right)
        {
            long long mid = left + (right - left + 1) / 2;
            if(mid * mid <= x)
                left = mid;
            else
                right = mid - 1;
        }
        return left;
    }

5.山脉数组的顶峰

在这里插入图片描述
题目链接

根据题目可知,山脉递增以后再递减,那么一定会存在相邻的两个数前者大于后者的情况,此时前者就是峰顶。

解法一:暴力求解

从i = 1下标依次遍历数组,如果nums[i-1] > nums[i],此时i-1位置就是峰顶。

解法二:二分求解

  • 如果nums[i] > nums[i-1],那么nums[i]之前一定是递增的,峰值还再后面,因此可以排除 i 之前的区间 left = mid;
  • 如果nums[i] < nums[i-1],那么i及后面的都不可能是峰值,right = mid - 1;
  • 未避免死循环和mid-1越界,求mid时应选择后面的一个
    int peakIndexInMountainArray(vector<int>& arr) {
        int left = 0;
        int right = arr.size()-1;

        while(left < right)
        {
            int mid = left + (right - left + 1)/ 2;
            if(arr[mid] > arr[mid-1])
                left = mid;
            else
                right = mid - 1;
        }
        return left;
    }

6.寻找峰值

在这里插入图片描述

任取⼀个点 i ,与前⼀个点 i - 1,会有如下两种情况:

  • arr[i] > arr[i - 1] :此时「右侧区域」⼀定会存在山峰(因为最右侧是负⽆穷),那么我们可以去右侧去寻找结果;
  • arr[i] < arr[i - 1] :此时「左侧区域」⼀定会存在山峰(因为最左侧是负⽆穷),那么我们可以去左侧去寻找结果。
  • 注意边界情况
    int findPeakElement(vector<int>& nums) 
    {
        int left = 0;
        int right= nums.size()-1;
        while(left < right)
        {
            //防止下标越界和死循环,mid总是取后一个
            int mid = left + (right - left + 1) / 2;

            if(nums[mid] > nums[mid-1])//去右边区域找
                left = mid;
            else
                right = mid - 1;
        }
        return left;
    }

7.寻找旋转排序数组中的最小值

在这里插入图片描述
题目链接

由于数组原本是一个有序的数组,那么旋转后数组就会变成含有两段有序元素的数组。
在这里插入图片描述

对于任意一个点 i 而言,我们就是要找C的位置

  • 如果nums[i]落在AB区间中,也就是nums[i] > nums[D],此时应该去 [i+1,D]区间中找,即left = mid + 1
  • 如果nums[i]落在CD区间中,也就是nums[i] < nums[D],此时应该去[C,i]区间中找,即right = mid;
  • 当区间长度变为1时,就是结果
    int findMin(vector<int>& nums) {
        int n = nums.size()-1;
        int left = 0;
        int right = n;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] > nums[n])
                left = mid + 1;
            else
                right = mid;
        }
        return nums[left];
    }

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

上海小学生古诗文大会2024年备考:吃透历年真题和知识点(持续)

一、小学生古诗文大会真题精选&#xff08;答案和解析见文末&#xff09; *1. 孟浩然的《宿建德江》是一首&#xff08;&#xff09;。 A.五言绝句 B.七言绝句 C.五言律诗 D.七言律诗 *2. 茕茕子立&#xff0c;形影相吊出自&#xff08;&#xff09; A.《出师表》 B.《…

常见Python GUI库分析

引言 在Python环境下进行桌面编程时&#xff0c;选择合适的GUI&#xff08;图形用户界面&#xff09;库至关重要。在Python环境下进行桌面编程GUI开发时&#xff0c;有多个优秀的库可供选择。以下是一些推荐的GUI库&#xff0c;包括它们的推荐理由、优劣势以及简单的demo示例。…

Deepspeed框架学习笔记

DeepSpeed 是由 Microsoft 开发的深度学习优化库,与PyTorch/TensorFlow等这种通用的深度学习框架不同的是,它是一个专门用于优化和加速大规模深度学习训练的工具,尤其是在处理大模型和分布式训练时表现出色。它不是一个独立的深度学习框架,而是依赖 PyTorch 等框架,扩展了…

C++20中lambda表达式新增加支持的features

1.弃用通过[]隐式捕获this&#xff0c;应使用[,this]或[,*this]显示捕获&#xff1a; namespace { struct Foo {int x{ 1 };void print(){//auto change1 [] { // badauto change1 [, this] { // good, this: referencethis->x 11;};change1();std::cout << "…

麒麟系统安装GPU驱动

1.nvidia 1.1显卡驱动 本机显卡型号:nvidia rtx 3090 1.1.1下载驱动 打开 https://www.nvidia.cn/geforce/drivers/ 也可以直接使用下面这个地址下载 https://www.nvidia.com/download/driverResults.aspx/205464/en-us/ 1.1.3安装驱动 右击&#xff0c;为run文件添加可…

【YOLO 系列】基于YOLOV8的智能花卉分类检测系统【python源码+Pyqt5界面+数据集+训练代码】

前言&#xff1a; 花朵作为自然界中的重要组成部分&#xff0c;不仅在生态学上具有重要意义&#xff0c;也在园艺、农业以及艺术领域中占有一席之地。随着图像识别技术的发展&#xff0c;自动化的花朵分类对于植物研究、生物多样性保护以及园艺爱好者来说变得越发重要。为了提…

接口自动化三大经典难题

目录 一、接口项目不生成token怎么解决关联问题 1. Session机制 2. 基于IP或设备ID的绑定 3. 使用OAuth或第三方认证 4. 利用隐式传递的参数 5. 基于时间戳的签名验证 二、接口测试中网络问题导致无法通过怎么办 1. 重试机制 2. 设置超时时间 3. 使用模拟数据 4. 网…

【STM32开发】GPIO最全解析及应用实例

目录 【1】GPIO概述 GPIO的基本概念 GPIO的应用 【2】GPIO功能描述 1.IO功能框图 2.知识补充 3.功能详述 浮空输入 上拉输入 下拉输入 模拟输入 推挽输出 开漏输出 复用开漏输出和复用推挽输出 【3】GPIO常用寄存器 相关寄存器介绍 4个32位配置寄存器 2个32位数据寄存器 1个32位…

Android的logcat日志详解

Android log系统 logcat介绍 logcat是android中的一个命令行工具&#xff0c;可以用于得到程序的log信息。下面介绍 adb logcat中的详细参数命令以及如何才能高效的打印日志&#xff0c;或把日志保存到我们指定的位置。 可以输入 adb logcat --help&#xff0c;查看一下一些简…

深入CSS 布局——WEB开发系列29

CSS 页面布局技术允许我们拾取网页中的元素&#xff0c;并且控制它们相对正常布局流、周边元素、父容器或者主视口/窗口的位置。 一、正常布局流&#xff08;Normal Flow&#xff09; CSS的布局基础是“正常流”&#xff0c;也就是页面元素在没有特别指定布局方式时的默认排列…

图神经网络(2)预备知识

1. 图的基本概念 对于接触过数据结构和算法的读者来说&#xff0c;图并不是一个陌生的概念。一个图由一些顶点也称为节点和连接这些顶点的边组成。给定一个图G(V,E), 其 中V{V1,V2,…,Vn} 是一个具有 n 个顶点的集合。 1.1邻接矩阵 我们用邻接矩阵A∈Rnn表示顶点之间的连接关…

AI自动生成PPT哪个软件好?如何自动生成专业级PPT?

新学期伊始&#xff0c;准备开学演讲稿的你是否还在为制作PPT而烦恼&#xff1f;别担心&#xff0c;现在有了AI的帮助&#xff0c;生成专业且吸引人的PPT变得轻而易举。 本文将为你揭秘4种高效的AI自动生成PPT的方法&#xff0c;让你在新学期的演讲中脱颖而出。无论是简洁明了…

数据权限的设计与实现系列6——前端筛选器组件Everright-filter使用探索

linear 功能探索 最终我们是需要使用 API 的方式&#xff0c;调用后端服务拉取数据填充筛选器组件&#xff0c;不过在探索阶段&#xff0c;直接用 API 方式&#xff0c;就需要构造 mock 数据&#xff0c;比较麻烦&#xff0c;因此先使用 Function 方式来进行功能验证。 组件初…

Visual Studio Code:让你的工作效率飞升的秘密武器

在现代软件开发环境中&#xff0c;效率已成为每个开发者追求的目标。而在众多编程工具中&#xff0c;Visual Studio Code&#xff08;简称VS Code&#xff09;凭借其强大的功能、轻量的界面和高度的可定制性&#xff0c;成为了全球开发者的首选。无论你是编写前端代码、后端服务…

软考(计算机技术与软件专业技术资格(水平)考试)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

SpringBoot教程(十五) | SpringBoot集成RabbitMq(消息丢失、消息重复、消息顺序、消息顺序)

SpringBoot教程&#xff08;十五&#xff09; | SpringBoot集成RabbitMq&#xff08;消息丢失、消息重复、消息顺序、消息顺序&#xff09; RabbitMQ常见问题解决方案问题一&#xff1a;消息丢失的解决方案&#xff08;1&#xff09;生成者丢失消息丢失的情景解决方案1&#xf…

C++三位状态比较排序

数组相同元素个数及按序 void 交换3个数升(int& A, int& B, int& C, bool& k) {int J 0;if (B > A&&A > C)J C, C B, B A, A J, k true;//231else if (C > A&&A > B)J A, A B, B J, k true;//213else if (A > B&a…

使用python+opencv解析图像和文本数据

1. 创建虚拟环境 新建文件夹, 并在文件夹中创建虚拟环境,可以使用Vscode打开文件夹, 然后在终端中输入以下命令: python -m venv venv2. 激活虚拟环境 在终端中输入以下命令: venv\Scripts\activate3. 安装依赖 在终端中输入以下命令: pip install opencv-pythonpip inst…

ArmSoM CM5 RK3576核心板推出,强势替代树莓派CM4

ArmSoM团队隆重推出全新的CM5 RK3576核心板&#xff0c;这款模块专为嵌入式开发者设计&#xff0c;凭借其强大的性能与丰富的扩展性&#xff0c;完美替代树莓派CM4&#xff0c;成为开发者们的理想选择。 CM5核心板采用了先进的RK3576 SoC&#xff0c;凭借卓越的计算能力和出色…

MapSet之二叉搜索树

系列文章&#xff1a; 1. 先导片--Map&Set之二叉搜索树 2. Map&Set之相关概念 目录 前言 1.二叉搜索树 1.1 定义 1.2 操作-查找 1.3 操作-新增 1.4 操作-删除(难点) 1.5 总体实现代码 1.6 性能分析 前言 TreeMap 和 TreeSet 是 Java 中基于搜索树实现的 M…