二分查找模板--从题目中讲解三大二分模板

二分查找的特点:最恶心、细节最多、最容易写出死循环的算法

目录

1.朴素的二分模板

1.1题目链接:704.二分查找

1.2题目描述:

1.3算法流程:

1.4算法代码:

1.5朴素二分模板:

2.查找左,右边界的二分模板

2.1题目链接:34.在排序数组中查找元素的第一个和最后一个位置

2.2题目描述:

2.3算法思路:

2.4算法代码

2.5左右边界的二分模板:

2.6左右边界模板的记忆方法:


1.朴素的二分模板

1.1题目链接:704.二分查找

1.2题目描述:
 

给定一个 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]之间。

1.3算法流程:

a.定义left,right指针分别指向数组的左右区间。

b.找到待查找区间的中间点mid,找到之后分三种情况讨论:

  1. arr[mid] == target说明正好找到,返回mid的值;
  2. arr[mid] > target 说明[mid,right]这段区间都大于target的,因此舍去右边区间,在左边[left, mid-1]的区间继续查找,即让right = mid - 1,然后重复2过程
  3. arr[mid] < target 说明[left,mid]这段区间的值都是小于target的,因此舍去左边区间,在右边[mid+1,right]区间继续查找,即让left = mid+1,然后重复2过程;

c.当left和right错开时,说明整个区间都没有这个数,返回-1

1.4算法代码:

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(target>nums[mid]){left = mid+1;}else if(target < nums[mid]){right = mid-1;}elsereturn mid;}return -1;}
};

1.5朴素二分模板:

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

2.查找左,右边界的二分模板

2.1题目链接:34.在排序数组中查找元素的第一个和最后一个位置

2.2题目描述:

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

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

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

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

2.3算法思路:

用的还是二分思想,就是根据数据的性质,在某种判断条件下将区间一分为二,然后舍去其中一个区间,然后再另一个区间内查找;

方便描述,用x表示该元素,resLeft表示左边界,resRight表示右边界。

寻找左边界思路:
我们注意到左边界划分的两个区间的特点:

  • 左边区间[left,resLeft - 1]都是小于x的;
  • 右边区间(包括左边界)[resLeft,right]都是大于等于x的;

因此,关于mid的落点,我们可以分为下面两种情况:

  • 当我们mid落在[left,resLeft - 1]区间的时候,也就是arr[mid] < target。说明[left,mid]都是可以舍去的,此时更新left到mid+1的位置,继续再[mid+1,right]上寻找左边界;
  • 当mid落在[resLeft, right]的区间的时候,也就是arr[mid] >= target。说明[mid+1,right](因为mid可能是最终结果,不能舍去)是可以舍去的,此时更新right到mid的位置,继续在[left, mid]上寻找左边界;
  • 由此,就可以通过二分,来快速寻找左边界;

注意:这里找中间元素需要向下取整

因为后续移动左右指针的时候:

  • 左指针:left = mid+1,是会向后移动的,因此区间是会缩小的;
  • 右指针:right = mid,可能会原地踏步(比如:如果向上取整的话,如果剩下1,2两个元素,left == 1,right == 2,mid == 2.更新区间之后,left,right,mid的值没有改变,就会陷入死循环)

因此一定要注意,当right = mid的时候,要向下取整。

寻找右边界思路:

寻右边界:

用resRight表示右边界;

我们注意到右边界的特点:

  • 左边区间(包括有边界)[left,resRight]都是小于等于x的;
  • 右边区间[resRight+1,right]都是大于x的;

因此,关于mid的落点,我们可以分为下面两种情况:

  • 当我们的mid落在[left,resRight]区间的时候,说明[left,mid-1](mid不可以舍去,因为有可能是最终结果)都是可以舍去的,此时更新left到mid的位置。
  • 当mid落在[resRight+1,right]的区间的时候,说明[mid,right]内的元素是可以舍去的,此时更新right到mid-1的位置;

由此,就可以通过二分,来快速寻找右边界;

注意:这里找中间元素需要向上取整。

  • 左值真:left = mid,可能会原地踏步(比如:如果向下取整的话,如果剩下1,2两个元素,left == 1,right == 2,mid == 1。更新区间之后,left,right,mid的值没有改变,就会陷入死循环)。
  • 右指针:right = mid-1,是会向前移动的,因此区间是会缩小的;

因此一定要注意,当right = mid的时候,要向下取整。

2.4算法代码

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {if(nums.size() == 0){return {-1,-1};}int begin = 0;//1.二分左端点int left = 0,right = nums.size()-1;while(left < right){int mid = left + (right - left)/2;if(nums[mid]>=target)right = mid;elseleft = mid+1;       }//判断是否有结果if(nums[left] != target) return {-1,-1};else begin = left;left = 0,right = nums.size()-1;while(left < right){int mid = left + (right - left + 1)/2;if(nums[mid]>target)right = mid-1;elseleft = mid;}return {begin,right};}
};

2.5左右边界的二分模板:
 

//寻找左边界
while (left < right)
{int mid = left + (right - left) / 2;if (......)left = mid + 1;else right = mid;
}
//寻炸右边界
while (left < right)
{int mid = left + (right - left +1) / 2;if (......)left = mid;else right = mid - 1;
}

2.6左右边界模板的记忆方法:

当只有两个元素,left指向左边的元素,right指向右边的元素。因为只有当left = right的时候才是找到边界。所以

当mid指向左边的元素时,想要left = right,就必须right = mid,且right向左,所以是寻找左边界且right = mid,left = mid+1。

当mid指向右边的元素时,想要left = right,就必须left = mid,且left向左,所以是寻找右边界且left = mid,right = mid-1。

mid指向右边的是,mid = left +(right-left+1)/2

mid指向左边的是,mid = left +  (right - left)/2

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络运维学习笔记(DeepSeek优化版) 022 HCIP-Datacom路由概念、BFD协议详解与OSPF第一课

文章目录 路由概念、BFD协议详解与OSPF第一课一、路由协议优先级与选路原则1.1 路由协议优先级对照表1.2 路由选路核心原则 二、BFD&#xff08;Bidirectional Forwarding Detection&#xff0c;双向转发检测&#xff09;的配置与应用2.1 双向心跳探测&#xff08;双端配置&…

单应性矩阵(homography)

利用单应性矩阵计算内外参矩阵 利用单应性矩阵解决问题 问题描述&#xff1a;

Scavenge算法的优缺点问题

Scavenge 的缺点是只能使用堆内存中的一半&#xff0c;这是由划分空间和复制机制所决定的。但 Scavenge 由于只复制存活的对象&#xff0c;并且对于生命周期短的场景&#xff0c;存活对象只占少部分&#xff0c;所以它在时间效率上有优异的表现。 由于 Scavenge 是典型的牺牲空…

丝杆支撑座间隙调整不当会带来哪些影响?

丝杆支撑座是一种用于支撑滚珠丝杆的零件&#xff0c;通常用于机床、数控机床、自动化生产线等高精度机械设备中。支撑座间隙调整不当会对机械设备的运行产生多方面的影响&#xff0c;接下来一起了解一下&#xff1a; 1、降低加工精度&#xff1a;在机械加工设备中&#xff0c;…

Unity:EasyRoad3D插件学习 二期

前言&#xff1a; 书接上回。 一、场景视图状态&#xff1a; 创建好道路以后&#xff0c;切换到第一个选项&#xff0c;场景视图状态&#xff0c;查看道路信息&#xff0c;Main Settings修改道路名称、类型&#xff0c;宽度&#xff0c;是否闭环。 RoadWidth改为15&#xff…

内网渗透-DLL和C语言加载木马

免杀进阶技术 1、DLL的定义与使用 DLL:Dynamic Link library,动态链接库&#xff0c;是一个无法自己运行&#xff0c;需要额外的命令或程序来对其接口进行调用&#xff08;类方法、函数&#xff09;。 (1)在DevCpp中创建一个DLL项目 (2)在dllmain.c中定义源代码函数接口 #i…

一洽让常见问题的快速咨询,触手可及

在客户服务场景中&#xff0c;重复性常见问题的处理效率直接影响用户体验与客服成本。针对重复性常见问题&#xff0c;如何以直观的方式呈现给用户&#xff0c;使其能够快速、精准地提出咨询&#xff0c;已成为提升客户满意度的关键因素。 一、传统客服模式的效率枷锁 用户咨…

WEB攻防-Java安全SPEL表达式SSTI模版注入XXEJDBCMyBatis注入

目录 靶场搭建 JavaSec ​编辑​编辑 Hello-Java-Sec(可看到代码对比) SQL注入-JDBC(Java语言连接数据库) 1、采用Statement方法拼接SQL语句 2.PrepareStatement会对SQL语句进行预编译&#xff0c;但如果直接采取拼接的方式构造SQL&#xff0c;此时进行预编译也无用。 3、…

树莓集团南京园区启航:数字经济新地标!

深耕数字产业&#xff0c;构筑生态闭环 树莓集团在数字产业领域拥有超过十年的深厚积累&#xff0c;专注于构建“数字产业”的融合生态链。其核心优势在于有效整合政府、产业、企业及高校资源&#xff0c;形成一个协同创新、价值共生的产业生态闭环系统。 赋能转型&#xff0c…

Redis之bimap/hyperloglog/GEO

bimap/hyperloglog/GEO的真实需求 这些需求的痛点&#xff1a;亿级数据的收集清洗统计展现。一句话&#xff1a;存的进取得快多维度 真正有价值的是统计。 统计的类型 亿级系统中常见的四种统计 聚合统计 统计多个集合元素的聚合结果&#xff0c;就是交差并等集合统计。 排…

nara wpe去混响学习笔记

文章目录 1.WPE方法去混响的基本流程1.1.基本流程 2.离线迭代方法3.在线求法3.1.回顾卡尔曼方法3.2.在线去混响递推滤波器G方法 nara wpe git地址 博客中demo代码下载 参考论文 NARA - WPE: A Python Package for Weighted Prediction Error Dereverberation in Numpy and Ten…

JavaScript函数、箭头函数、匿名函数

1.示例代码(包括用法和注意事项) <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>JS-函数</title…

练习:求平方根

需求&#xff1a;键盘录入一个大于等于2的整数x&#xff0c;计算并返回x的平方根。结果只保留整数部分&#xff0c;小数部分将被舍去。 代码一&#xff1a; //求平方根 //方法一&#xff1a; package Online; import java.util.Scanner; public class SquareRoot {public sta…

win10 安装后的 系统盘的 分区

win10 安装后的 系统盘的 分区 MBR 分区 GPT 分区

反向 SSH 隧道技术实现内网穿透

反向 SSH 隧道技术实现内网穿透 场景描述 有一台内网的 Linux PC 机&#xff0c;想在其他地方&#xff08;如家中&#xff09;使用浏览器&#xff0c;在浏览器中能够使用内网 Linux PC 机的命令行。 实现思路 内网 Linux PC 机在内网可以使用 SSH 进行连接&#xff0c;但内…

[MRCTF2020]套娃

一。 按F12看源代码 发现代码 读代码发现 1.我们传的参数中不能存在_和%5f&#xff0c;可以通过使用空格来代替_&#xff0c;还是能够上传成功。 2.正则表达式"/^23333/ " &#xff0c;开头结尾都被 " " 和 " /"&#xff0c;开头结尾都被&qu…

基于Windows11的WSL2通过Ollama平台安装部署DeepSeek-R1模型

DeepSeek-R1模型各参数版本硬件要求 一、在Windows上安装Linux子系统WSL2 检查电脑是否支持虚拟化&#xff0c;按住<font style"color:rgb(199, 37, 78);background-color:rgb(249, 242, 244);">WindowsR</font>输入<font style"color:rgb(199,…

PHP回调后门小总结

目录 1.call_user_func 函数说明 蚁剑连接 2.数组操作造成的单参数回调后门 array_filter 函数说明 蚁剑连接 array_map 函数说明 蚁剑连接 3.二参数回调函数 uasort 函数说明 uksort array_reduce array_udiff 蚁剑连接 4.三参数的回调后门 array_walk 函数说…

MinGW与使用VScode写C语言适配

压缩包 通过网盘分享的文件&#xff1a;MinGW.zip 链接: https://pan.baidu.com/s/1QB-Zkuk2lCIZuVSHc-5T6A 提取码: 2c2q 需要下载的插件 1.翻译 找到VScode页面&#xff0c;从上数第4个&#xff0c;点击扩展&#xff08;以下通此&#xff09; 搜索---Chinese--点击---安装--o…

-PHP 应用SQL 盲注布尔回显延时判断报错处理增删改查方式

#PHP-MYSQL-SQL 操作 - 增删改查 1 、功能&#xff1a;数据查询(对数据感兴趣&#xff09; 查询&#xff1a; SELECT * FROM news where id$id 2 、功能&#xff1a;新增用户&#xff0c;添加新闻等&#xff08;对操作的结果感兴趣&#xff09; 增加&#xff1a; INSERT INT…