【面试经典 150 | 二分查找】在排序数组中查找元素的第一个和最后一个位置

news2024/12/24 21:12:35

文章目录

  • 写在前面
  • Tag
  • 题目来源
  • 题目解读
    • 方法一:二分查找
    • 方法二:使用库函数
  • 知识回顾
    • 二分查找的三种写法与三个问题
    • 常用的二分库函数
  • 写在最后

写在前面

本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……

专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:

  • Tag:介绍本题牵涉到的知识点、数据结构;
  • 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
  • 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
  • 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
  • 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。

Tag

【数组】【二分查找】


题目来源

34. 在排序数组中查找元素的第一个和最后一个位置


题目解读

方法一:二分查找

对于有序数组中搜索指定元素问题,我们应该优先想到二分查找方法。题目有要求解法的时间复杂度必须为 O ( l o g n ) O(logn) O(logn),那本题基本确定需要使用二分查找法解题。

思路

我们只需要写出一个函数找出数组中 target 第一次出现的位置。使用二分查找轻松实现。还有一些实现细节,见代码中的注释。

代码

class Solution {
public:
    // 【闭区间写法】找出 nums[i] >= target 的最小的 i
    int lower_bound(const vector<int>& nums, int target) {

        int left = 0, right = nums.size() - 1;
        while (left <= right) {     // 区间不为空
            // 注意指针的指向变化
            int mid = left + ((right - left) >> 1);
            if (nums[mid] < target) {
                left = mid + 1;
            }
            else {
                right = mid - 1;
            }
        }
        return left;
    }

    vector<int> searchRange(vector<int>& nums, int target) {
        int start = lower_bound(nums, target);
        if (start == nums.size() || nums[start] != target) {
            return {-1, -1};
        }

        // 如果 start 存在,那么 end 必定存在
        int end = lower_bound(nums, target + 1) - 1;
        return {start, end};
    }
};

复杂度分析

时间复杂度: O ( l o g n ) O(logn) O(logn)

空间复杂度: O ( 1 ) O(1) O(1)

方法二:使用库函数

对于上述手写二分查找的函数,C++ 标准库中有对应的函数 lower_bound \texttt{lower\_bound} lower_bound 实现相同的功能。不论是库函数,还是手写二分查找都需要掌握。

代码

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int start = lower_bound(nums.begin(), nums.end(), target) - nums.begin();
        if (start == nums.size() ||  nums[start] != target) {
            return {-1, -1};
        }

        int end = lower_bound(nums.begin(), nums.end(), target + 1) - nums.begin() - 1;
        return {start, end};
    }
};

知识回顾

二分查找的三种写法与三个问题

二分查找有三种写法:闭区间、左闭右开和开区间写法,无论是哪种写法,始终都要关注三个问题:

  • 何时退出循环,二分查找据此有了三种写法
  • 指针如何移动
  • 最后返回什么

关于以上三种写法与三个问题,可以参考 【面试经典 150 | 二分查找】搜索插入位置。

常用的二分库函数

lower_bound(beg,   end,   val) \texttt{lower\_bound(beg, end, val)} lower_bound(beg, end, val)
返回一个迭代器,表示 第一个不小于(大于等于) val 的元素,如果不存在这样的元素则返回 end 迭代器。
upper_bound(beg,   end,   val) \texttt{upper\_bound(beg, end, val)} upper_bound(beg, end, val)
返回一个迭代器,表示 第一个大于 val 的元素,如果不存在这样的元素则返回 end 迭代器。
equal_range(beg,   end,   val) \texttt{equal\_range(beg, end, val)} equal_range(beg, end, val)
返回一个 pair,其 first 成员是 lower_bound \texttt{lower\_bound} lower_bound 返回的迭代器,second 成员是 upper_bound \texttt{upper\_bound} upper_bound 返回的迭代器。
binary_search(beg,   end,   val) \texttt{binary\_search(beg, end, val)} binary_search(beg, end, val) 返回一个 bool 值,指出序列中是否包含等于 val 的值。

以上每一个函数都提供一个第二版本,这个版本可以自定义比较操作。

写在最后

如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。

最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。

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

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

相关文章

实战1-批量爬取百度图片(上)

任务需求&#xff1a;输入关键字下载100个图片保存到本地&#xff0c;每个关键字单独存放一个文件夹&#xff08;GUI版&#xff09; 任务描述&#xff1a;当输入关键字时会爬取100个与关键词有关的图片到本地每个关键词单独保存到一个文件夹中&#xff0c;比如说我输入黑客下载…

【技术变现之道】如何打造IT行业的超级个体?

前言 在当今的数字化时代&#xff0c;IT行业蓬勃发展&#xff0c;为具备技术专长的个人提供了无限的可能性。想要成为IT行业的超级个体&#xff0c;实现知识与技能的变现吗&#xff1f;以下是一些高效途径&#xff0c;助你一臂之力&#xff01; 1. 独立接单外包 1&#xff09…

C语言—常用字符串函数剖析

字符串函数 cplusplus.com/reference/cstring/ 更多没有总结到的函数大家可以自行查阅 这篇文章只是把最需要知道的函数做一个总结 strlen size_t strlen ( const char * str );字符串已经 ‘\0’ 作为结束标志&#xff0c;strlen函数返回的是在字符串中 ‘\0’ 前面出现的…

Android开发基础:Activity之间的跳转 向下一个Activity传递数据 给上一个Activity返回数据

目录 一&#xff0c;使用Intent在Activity之间跳转 1.显示使用Intent 2.隐式使用Intent 二&#xff0c;携带数据的跳转 1.Bundle 三&#xff0c;返回数据给上一个Activity 1.registerForActivityResult 一&#xff0c;使用Intent在Activity之间跳转 一个Android应用中包…

语言的未来:深度学习在自然语言处理中的革命

语言的未来&#xff1a;深度学习在自然语言处理中的革命 1 引言 自古以来&#xff0c;语言就是人类表达思想、传递信息、进行社会互动的基石。语言的复杂性既体现在其变化多端的语义、句法和语用层面&#xff0c;同时也反映在人类如何理解和产生自然语言的深奥之中。在这一节中…

java项目的构建工具-Maven

黑马程序员JavaWeb开发教程 文章目录 一、概述1、介绍&#xff08;1&#xff09;介绍&#xff08;2&#xff09;Maven的作用&#xff08;3&#xff09;官网&#xff08;4&#xff09;仓库 2、安装 二、IDEA 集成 Maven1、配置Maven环境2、创建Maven项目&#xff08;1&#xff0…

java 红黑树

01.红黑树的定义&#xff1a; 每一个结点有五个属性&#xff1a;

Jmeter测试学习笔记

第一章 jmeter基础知识 一.Jmeter工具中的组件 1.测试计划&#xff1a;Jmeter测试的起点。容器。 2.线程组&#xff1a;代表一定的用户 3.取样器&#xff1a;发送请求的最小单元 4.逻辑控制器&#xff1a;处理请求逻辑 5.前置处理器&#xff1a;请求之前的操作 6.后置处…

docker部署的nginx配置ssl证书https

申请ssl证书&#xff0c;已腾讯的免费证书为例 2.上传证书到linux服务器 2.1 映射ssql目录 首先确保容器命令已映射宿主机目录&#xff0c;不一定是ssl&#xff0c;也可以是其他路径。 2.2 上传文件到指定路径 以我映射的ssl路径为例&#xff0c;我上传到宿主机的 /usr/local…

字母加密(C语言)

一、题目&#xff1b; 为使电文保密&#xff0c;往往按一定规律将其转换成密码&#xff0c;收报人再按约定的规律将其译回原文。例如&#xff0c;可以按以下规律将电文变成密码&#xff1a;将字母A变成字母E&#xff0c;a变成e&#xff0c;即变成其后的第4个字母&#xff0c;W…

【Shell语言】linux中awk命令

linux中awk命令 看这里放声嘶吼谁也不舍得沉默 宽阔也抓不住我下一秒钟的echo ——《暂时失控》苏打绿 awk命令简介 AWK 是一种处理文本文件的语言&#xff0c;是一个强大的文本分析工具。 之所以叫 AWK 是因为其取了三位创始人 Alfred Aho&#xff0c;Peter Weinberger, 和 B…

密码学 | 数字签名 + 数字证书

&#x1f951;原文&#xff1a;数字签名和数字证书的原理解读 - 知乎 &#x1f951;声明&#xff1a;后文图中若未明确指明&#xff0c;默认是 Bob 的公钥或私钥。 Step1&#xff1a;Bob 有两把钥匙&#xff0c;一把是公钥&#xff0c;另一把是私钥。 Step2&#xff1a;Bob 把…

Redis中的BigKey

Redis中的BigKey 文章目录 Redis中的BigKey什么是BigKey&#xff1f;BigKey的危害找到Bigkey删除BigKey优化BigKeyBigKey对持久化的影响对AOF日志的影响对AOF重写和RDB的影响 什么是BigKey&#xff1f; 大 key 并不是指 key 的值很大&#xff0c;而是 key 对应的 value 很大。…

Docker操作容器打包(commit),压缩(save),挂载(load)

文章目录 前言一、容器打包二、将镜像压缩成tar包三、将tar包挂载为镜像结束 前言 将容器打包成镜像时&#xff0c;你正在将应用程序及其所有依赖项、文件和配置文件捆绑到一个可移植的、独立的单元中。这样做可以确保您的应用程序在不同环境中具有一致的运行方式&#xff0c;…

使用自己训练好的模型YOLOv8进行X-AnyLabeling自动标注

目录 1. 下载项目2. 创建环境3. 运行程序3.1 自行下载和添加官方模型3.2 使用自己训练好的模型标注自己的数据集 本机环境&#xff1a;win 10&#xff0c; GPU 1. 下载项目 git clone https://github.com/CVHub520/X-AnyLabeling.git2. 创建环境 仔细查看项目的README文件 …

FastGPT+ChatGLM3本地部署

FastGPTChatGLM本地部署 本地部署硬性要求&#xff1a;显存13g以上 关于环境的安装就不多赘述&#xff0c;conda pip 可以解决大部分问题 ChatGLM本地运行 m3e-basechatglm3-6b 在huggingface上可以下载上述模型&#xff0c;如果没有梯子可以使用huggingface镜像 从git…

Linux shell 脚本基础与部署SpringCloud实战

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

Java学习笔记零基础入门1

目录 第一章 Java概述 1.1 什么是程序 1.2 Java 技术体系平台 1.3 Java 重要特点 1.4 Java 的开发工具 4.1 工具选择 1.5 Java 运行机制及运行过程 5.1 Java 语言的特点&#xff1a;跨平台性 5.2 Java 核心机制-Java 虚拟机 [JVMjavavirtual machine] 1.6 什么是JDK&…

C++ PTA 天梯赛 L1-003 个位数统计 L1-005 考试座位号 【范围for循环】【. 与 -> 访问成员】

L1-003 个位数统计 最后一个测试点考察的是当N特别大时&#xff0c;如果用整数存会数据溢出&#xff0c;改成字符串可以增大范围 知识点&#xff1a; 1.范围 for 循环&#xff0c;它对于遍历容器&#xff08;比如字符串&#xff09;中的元素非常方便。在这里&#xff0c;N 是…

JavaEE初阶Day 10:多线程(8)

目录 Day 10&#xff1a;多线程&#xff08;8&#xff09;单例模式阻塞队列1. 生产者消费者模型1.1 生产者消费者模型解耦合1.2 生产者消费者模型削峰填谷 2. 生产者消费者代码3. 阻塞队列实现 Day 10&#xff1a;多线程&#xff08;8&#xff09; 单例模式 单例模式&#xf…