二分查找(非朴素)--在排序数组中查找元素的第一个和最后一个位置

 个人主页:Lei宝啊 

愿所有美好如期而遇


目录

本题链接 

输入描述

输出描述

算法分析

1.算法一:暴力求解

2.算法二:朴素二分算法

3.算法三:二分查找左右端点

3.1查找左端点

3.1.1细节一:循环条件

3.1.2细节二:mid的值

3.2查找右端点

解题源码 


本题链接 

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

输入描述

我们选择示例1,接口为vector<int> searchRange(vector<int>& nums, int target) ,向nums中写入非递减的数字,也就是说可以有多个重复的相同数字。

输出描述

由于nums中可能有多个值与target相等,所以我们需要记录这个区间的左端点和右端点,然后返回这个区间,如果找不到,则区间为[-1,-1]。

算法分析

1.算法一:暴力求解

直接从左到右扫描这个数组,通过begin和end变量来记录相等于target的起始位置和结束位置,找不到则返回[-1,-1],时间复杂度为O(N)。

2.算法二:朴素二分算法

直接二分,如果寻找的target在nums中只有一个,那么时间复杂度为log(N),但是如果有多个的话,我们还是需要去遍历mid的左边和mid的右边,如果整个数组所有值都与target相等,就相当于要遍历整个数组,时间复杂度仍然为O(N),这里我们使用朴素二分算法仍然不是最优的。

3.算法三:二分查找左右端点
3.1查找左端点

我们可以将数组分成两个区间,以[5,7,7,8,8,10],target = 8为例,既然我们要找左端点,也就是最左边的那个8,所以我们将数组分成小于target的区间大于等于target的区间,即[5,7,7]   [8,8,10]这两个区间。(lhs意为left side hand即左手边,rhs意为right side hand即右手边)

我们定义一个mid,mid = lhs + (rhs - lhs) / 2,并且有两种结果:

  • 当nums[mid] < target ,lhs = mid + 1;
  • 当nums[mid] >= target, rhs = mid;

你可能会问,为什么rhs = mid, 按照我们朴素二分算法的理解,应该是rhs = mid - 1, 我们可以举个例子,如果说mid = 3,也就是上面最左边的8,那么再怎么样我们也无法找到左端点了。

同时按照我们上面的两种结果,我们也可以发现一个事实,就是rhs永远不会出他的区间,lhs是可以跨区间的,当lhs == rhs时,也就代表着循环结束了。

所以这就是全部了吗?当然不是,他还有其他细节,这些细节一但注意不到,就是一个接一个的死循环。

3.1.1细节一:循环条件

朴素二分算法循环条件是lhs <= rhs,那么我们这里也是这样吗?上面我们提过一个事实,就是说当lhs == rhs时就已经结束了,而且正好是我们的左端点,所以说我们不用再去判断相等的情况,你可能会说,碰巧罢了,你这是能找到结果,你要是找不到呢?如果nums里全部大于target呢?如果nums里全部小于target呢?那我们分三种情况:

所以我们不需要判断lhs == rhs这种情况,因为我们上述三种情况就是本题的所有情况,而我们也证实了当lhs == rhs时就是我们的结果,要么找到,要么就找不到。

但是有人会犯倔,我嫌麻烦,还得想这么多东西,不就多判断一次嘛?我就用lhs <= rhs, 有问题吗?还是分三种情况,运气好点就不死循环。

所以我们循环条件也有两个细节:

  • 细节一:无需判断lhs == rhs,因为此时已经是结果了。
  • 细节二: 如果真的比较了,可能会死循环,在leetcode众多测试用例中,一定是错的。
3.1.2细节二:mid的值

我们上面直接让mid = lhs + (rhs - lhs) / 2; 可能你也没有思考为什么,可不可以,事实上,在查找左端点时这样正好可以,但是放在查找右端点上就是死循环,那么右端点mid怎么算?

mid = lhs + (rhs - lhs + 1) / 2;那么我们把这个用在左端点上看看效果。

我们可以发现:

  • 选择第一种方式,mid的值偏向于左边下标
  • 选择第二种方式,mid的值偏向于右边下标 

细节很多,不注意就死循环,但是我们不要死记硬背,要去理解,怎么样就死循环了,这才是我们该做的。

3.2查找右端点

查找右端点和查找左端点思路完全相同,只是有些细节不同,我们这里指出:

  1. 区间的划分:大于target的区间的小于等于target的区间
  2. mid的计算:mid = lhs + (rhs - lhs + 1) / 2;

剩下的就是一个模子了。 

解题源码 

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
        
        vector<int> v(2,-1);
        if(nums.size() <= 0)  return v;

        //计算左端点
        int lhs = 0, rhs = nums.size() - 1, mid = lhs + (rhs - lhs) / 2;

        while(lhs < rhs)
        {
            //分区间
            if(nums[mid] < target) lhs = mid + 1;   //小于区间
            else  rhs = mid;                        //大于等于区间        

            mid = lhs + (rhs - lhs) / 2;
        }
        
        if(nums[rhs] == target) v[0] = rhs;

        //计算右端点
        lhs = 0, rhs = nums.size() - 1, mid = lhs + (rhs - lhs + 1) / 2;

        while(lhs < rhs)
        {
            //分区间
            if(nums[mid] > target) rhs = mid - 1;   //大于区间
            else  lhs = mid;                        //小于等于区间        

            mid = lhs + (rhs - lhs + 1) / 2;
        }
        
        if(nums[rhs] == target) v[1] = rhs;

        return v;
    }
};

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

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

相关文章

【前端基础】——原型与原型链详解,看一篇即可【图文版】

前言 本文旨在通过图文的方式&#xff0c;一步步回顾原型链的整个流程是如何运作的&#xff0c;如果你刚好在电脑旁边&#xff0c;不妨跟着我的思路&#xff0c;一起走一遍敲一遍代码流程&#xff0c;你会发现原型链并没有你想的那么复杂。 new关键字 我们先看这一个代码&am…

华锐三维云展平台 | VR在线展览云平台提供定制化虚拟展厅制作工具

随着科技的飞速发展&#xff0c;互联网技术的不断革新&#xff0c;广州华锐互动顺应时代需求&#xff0c;开发了VR在线展览云平台&#xff0c;用户可以在平台上自主创建属于自己的3D展厅。VR在线展览云平台正改变着传统展览行业的模式&#xff0c;为参展者提供更高效、更便捷、…

vue3中怎么巧妙的去运用jsx?

文章目录 概要JSX / TSX?安装配置封装JsxRender.vue使用JsxRender.vue怎么巧妙的去使用它?Demo下载 概要 我们都知道vue3是支持用jsx/tsx&#xff0c;但是好像从来都没有人告诉我们应该怎么运用到项目当中&#xff0c;下面是我觉得不错的一种使用方式&#xff0c;分享给大家…

二级路由的配置以及注意项

二级路由 比如说LayOut组件是父亲&#xff0c;LayOut和ArtComp是儿子&#xff0c;那我们怎么给儿子配路由呢&#xff1f; 1、首先在router下的index.js导入组件&#xff0c;配置规则&#xff0c;详细如下 // 导入路由相关组件 import LayOut from /views/LayOut import UserC…

IntelliJ IDEA常用快捷键

【1】创建内容&#xff08;新建&#xff09;&#xff1a;altinsert 【2】main方法&#xff1a;psvm 【3】输出语句&#xff1a;sout 【4】复制行&#xff1a;ctrld 【5】删除行&#xff1a;ctrly&#xff08;很多编辑器ctrly是前进操作&#xff0c;如果选择 Delete Line&…

C++内联函数与引用(超详细)

文章目录 前言一、内联函数1.为什么会存在内联函数2.什么是内联函数3.内联函数注意事项 二、引用1.什么是引用2.引用的特性3.常引用4.引用使用场景5.引用与指针 总结 前言 一、内联函数 1.为什么会存在内联函数 &#x1f9d0;&#x1f9d0;首先我们介绍内联函数之前&#xf…

NVMe over Fabrics:概念、应用和实现

对于大部分人来说&#xff0c;NVMe over Fabrics&#xff08;简称NVMf&#xff09;还是个新东西&#xff0c;因为其第一个正式版本的协议在今年6月份才发布。但是这并不影响人们对NVMf的关注&#xff0c;因为这项依托于NVMe的技术很可能继续改变存储市场格局。 NVMf的贡献在于…

USB -- STM32F103复合设备(HID+MassStorage)传输讲解(十)

目录 链接快速定位 前沿 1 描述符讲解 1.1 设备描述符 1.2 配置描述符 1.3 接口描述符 1.4 功能描述符 1.5 端点描述符 1.6 字符串描述符 1.7 报告描述符 2 运行演示 链接快速定位 USB -- 初识USB协议&#xff08;一&#xff09; 源码下载请参考链接&#xff1a;…

vivado CDC约束-“设置总线倾斜”对话框

“设置总线倾斜”对话框 在AMD Vivado™ IDE中&#xff0c;可以通过多种方式设置总线偏斜约束&#xff1a; •通过时间约束编辑器。选择窗口 → 时间限制 → 断言 → 设置总线倾斜。从“时序约束编辑器”中&#xff0c;可以添加、删除或修改总线扭曲约束。 注意&#…

【VSCode】关闭双击shift出现搜索

原因 有时候总是手滑按两下shift&#xff0c;每次都会弹出如下图的搜索框&#xff0c;导致很不方便 解决办法 找到该文件 C:\Users\admin\.vscode\extensions\k--kato.intellij-idea-keybindings-1.5.12\package.json&#xff08;admin是自己的用户名&#xff09; 然后关键字…

【MySQL视图特性】

目录&#xff1a; 前言视图基本使用创建视图查看视图内容修改内容测试删除视图 视图规则和限制 前言 剑指offer&#xff1a;一年又12天 视图 视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图也是带有名称的列和行内容&#xff0c;对视图内容的…

Java集合/泛型篇----第二篇

系列文章目录 文章目录 系列文章目录前言一、说说List,Set,Map三者的区别二、Array与ArrayList有什么不一样?三、Map有什么特点四、集合类存放于 Java.util 包中, 主要有几 种接口前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。…

系列四、Eureka自我保护

一、Eureka自我保护 1.1、故障现象 保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式&#xff0c;Eureka Server将会尝试保护其服务注册表中的信息&#xff0c;不再删除服务注册表中的数据&#xff0c;也就是不会注销任何微服务。如…

学生信息管理系统winform+sqlserver

学生信息管理系统winformsqlserver Winform作为一个强大的桌面应用程序开发工具&#xff0c;具有丰富的图形化界面编程组件&#xff0c;可以快速构建出用户友好的界面。使用这个工具&#xff0c;我能够轻松设计出适合学生信息管理系统的各类窗体&#xff0c;比如学生信息录入窗…

------- 计算机网络基础

1.1概述 是什么? 答出独立计算机通信线路连接实现资源共享 计算机网络组成 从组成部分看: 硬件软件协议 从工作方式看: 边缘部分和核心部分 从功能组成看: 通信子网和资源子网 计算机网络性能指标 速率是指数据传输的物理速度&#xff0c;吞吐量是指实际的数据传输…

Redis:原理速成+项目实战——Redis的Java客户端

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理速成项目实战——Redis常见命令&#xff08;数据结构、常见命令总结&#xff09; &#x1f4da;订阅专栏&…

Qt Creator可视化交互界面exe快速入门5

上一期介绍了加法计算器,本期介绍QObject定时器。 首先一样先建个工程,比如我这项目名为QObject 本期的任务就是制作图片在界面上显示,然后每秒定时切换,点击另一个暂停按钮,可以定格当前图片,即取消定时切换功能。 显示图片的我们可以使用显示里面的label 这个用于显示…

STM32+Codesys工业软件PLC解决方案

工业控制系统在现代制造和自动化领域扮演着关键角色, 基于IEC 61131-3 标准的控制器编程开发软件平台CODESYS&#xff0c;适用于多种行业的控制系统的开发,使用户方便快捷地对自动化工程进行编程和配置&#xff0c;完成项目开发、软件测试和应用调试。 本次STM32联合合作伙伴C…

设计模式(4)--对象行为(8)--状态

1. 意图 允许一个对象在其内部状态改变时改变它的行为。 2. 三种角色 上下文环境(Context)、抽象状态(State)、具体状态(Concrete State) 3. 优点 3.1 将与特定状态相关的行为局部化&#xff0c;并且将不同状态的行为分割开来。 3.2 使得状态转换显式化。 3.3 State对象可被共…

超详细YOLOv8姿态检测全程概述:环境、训练、验证与预测详解

目录 yolov8导航 YOLOv8&#xff08;附带各种任务详细说明链接&#xff09; 搭建环境说明 不同版本模型性能对比 不同版本对比 参数解释 模型解释 训练 训练示意代码 训练数据与.yaml配置方法 .yaml配置 数据集路径 标签数据说明 训练参数说明 训练过程示意及输出…