码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 【算法面试】在排序数组中查找元素的第一个和最后一个位置:详细题解


    目录

    题目描述

    示例

    示例 1:

    示例 2:

    示例 3:

    问题分析

    详细步骤

    解决方法

    方法 1:标准二分查找(分开查找第一个和最后一个)

    方法 2:优化版二分查找(合并查找逻辑)

    方法 3:带调试信息的版本

    总结

    博主v:XiaoMing_Java


    题目描述

    在处理有序数组时,一个常见的问题是查找特定元素的起始和结束位置。给定一个按照非递减顺序排列的整数数组 nums 和一个目标值 target,我们需要找到目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。

    示例

    示例 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]

    问题分析

    由于数组是有序的,因此可以利用二分查找的方法来高效地解决这个问题。二分查找的时间复杂度为 O(log n),非常适合查找任务。

    为了找到目标值的起始和结束位置,我们可以分别使用两次二分查找:

    1. 第一次查找目标值的起始位置。
    2. 第二次查找目标值的结束位置。

    详细步骤

    1. 初始化:设置 left 为数组的起始索引 0,right 为数组的末尾索引 n-1。
    2. 查找起始位置:
      • 使用二分查找,如果找到目标值,则继续向左半部分查找,直到找到最左边的目标值。
    3. 查找结束位置:
      • 使用二分查找,如果找到目标值,则继续向右半部分查找,直到找到最右边的目标值。
    4. 组合结果:返回找到的起始位置和结束位置。

    解决方法

    方法 1:标准二分查找(分开查找第一个和最后一个)

    以下是实现二分查找的一种标准方法,通过两次二分查找分别查找第一个和最后一个目标值的位置:

    1. // 两次二分查找,分开查找第一个和最后一个
    2. // 时间复杂度 O(log n), 空间复杂度 O(1)
    3. // [1,2,3,3,3,3,4,5,9]
    4. public int[] searchRange2(int[] nums, int target) {
    5. int left = 0;
    6. int right = nums.length - 1;
    7. int first = -1;
    8. int last = -1;
    9. // 找第一个等于target的位置
    10. while (left <= right) {
    11. int middle = (left + right) / 2;
    12. if (nums[middle] == target) {
    13. first = middle;
    14. right = middle - 1; // 重点
    15. } else if (nums[middle] > target) {
    16. right = middle - 1;
    17. } else {
    18. left = middle + 1;
    19. }
    20. }
    21. // 最后一个等于target的位置
    22. left = 0;
    23. right = nums.length - 1;
    24. while (left <= right) {
    25. int middle = (left + right) / 2;
    26. if (nums[middle] == target) {
    27. last = middle;
    28. left = middle + 1; // 重点
    29. } else if (nums[middle] > target) {
    30. right = middle - 1;
    31. } else {
    32. left = middle + 1;
    33. }
    34. }
    35. return new int[] { first, last };
    36. }

    方法 2:优化版二分查找(合并查找逻辑)

    为了代码更简洁,可以将查找最左和最右位置的逻辑合并到一个函数中,并通过传递额外参数来控制查找方向:

    1. public int[] searchRange(int[] nums, int target) {
    2. int first = findBound(nums, target, true);
    3. int last = findBound(nums, target, false);
    4. return new int[] { first, last };
    5. }
    6. private int findBound(int[] nums, int target, boolean isFirst) {
    7. int left = 0;
    8. int right = nums.length - 1;
    9. int bound = -1;
    10. while (left <= right) {
    11. int middle = left + (right - left) / 2;
    12. if (nums[middle] == target) {
    13. bound = middle;
    14. if (isFirst) {
    15. right = middle - 1; // 查找最左位置
    16. } else {
    17. left = middle + 1; // 查找最右位置
    18. }
    19. } else if (nums[middle] > target) {
    20. right = middle - 1;
    21. } else {
    22. left = middle + 1;
    23. }
    24. }
    25. return bound;
    26. }

    方法 3:带调试信息的版本

    为了更好地理解算法,可以添加调试信息来跟踪程序执行过程:

    1. public int[] searchRange(int[] nums, int target) {
    2. int first = findBound(nums, target, true);
    3. int last = findBound(nums, target, false);
    4. return new int[] { first, last };
    5. }
    6. private int findBound(int[] nums, int target, boolean isFirst) {
    7. int left = 0;
    8. int right = nums.length - 1;
    9. int bound = -1;
    10. while (left <= right) {
    11. int middle = left + (right - left) / 2;
    12. System.out.println("Left: " + left + ", Mid: " + middle + ", Right: " + right);
    13. if (nums[middle] == target) {
    14. bound = middle;
    15. if (isFirst) {
    16. right = middle - 1; // 查找最左位置
    17. } else {
    18. left = middle + 1; // 查找最右位置
    19. }
    20. } else if (nums[middle] > target) {
    21. right = middle - 1;
    22. } else {
    23. left = middle + 1;
    24. }
    25. }
    26. System.out.println(isFirst ? "First bound found at: " + bound : "Last bound found at: " + bound);
    27. return bound;
    28. }

    总结

    通过使用二分查找的方式,我们可以在 O(log n) 的时间复杂度内高效地找到排序数组中目标值的起始和结束位置。本文展示了多种实现方法,包括标准二分查找、优化版二分查找以及带调试信息的版本,以帮助读者更好地理解并应用这种算法。希望这些方法能够帮助你解决实际开发中的问题,确保程序顺利运行。

     如果本文对你有帮助 欢迎 关注、点赞、收藏、评论!!!

    博主v:XiaoMing_Java

     📫作者简介:嗨,大家好,我是 小 明(小明java问道之路),互联网大厂后端研发专家,2022博客之星TOP3 / 博客专家 / CSDN后端内容合伙人、InfoQ(极客时间)签约作者、阿里云签约博主、全网5万粉丝博主。


    🍅 文末获取联系 🍅  👇🏻 精彩专栏推荐订阅收藏 👇🏻

    专栏系列(点击解锁)

    学习路线(点击解锁)

    知识定位

    🔥Redis从入门到精通与实战🔥

    Redis从入门到精通与实战

    围绕原理源码讲解Redis面试知识点与实战

    🔥MySQL从入门到精通🔥

    MySQL从入门到精通

    全面讲解MySQL知识与企业级MySQL实战

    🔥计算机底层原理🔥

    深入理解计算机系统CSAPP

    以深入理解计算机系统为基石,构件计算机体系和计算机思维

    Linux内核源码解析

    围绕Linux内核讲解计算机底层原理与并发

    🔥数据结构与企业题库精讲🔥

    数据结构与企业题库精讲

    结合工作经验深入浅出,适合各层次,笔试面试算法题精讲

    🔥互联网架构分析与实战🔥

    企业系统架构分析实践与落地

    行业最前沿视角,专注于技术架构升级路线、架构实践

    互联网企业防资损实践

    互联网金融公司的防资损方法论、代码与实践

    🔥Java全栈白宝书🔥

    精通Java8与函数式编程

    本专栏以实战为基础,逐步深入Java8以及未来的编程模式

    深入理解JVM

    详细介绍内存区域、字节码、方法底层,类加载和GC等知识

    深入理解高并发编程

    深入Liunx内核、汇编、C++全方位理解并发编程

    Spring源码分析

    Spring核心七IOC/AOP等源码分析

    MyBatis源码分析

    MyBatis核心源码分析

    Java核心技术

    只讲Java核心技术

  • 相关阅读:
    基于石墨烯的光电探测传感器研究
    【OpenCV 图像处理 Python版】OpenCV 简介及安装
    spring框架Bean的作用域?对需要保持会话状态的bean应使用prototype作用域?为啥?
    建表时如何合理选择字段类型
    小工具推荐:FastGithub的下载及使用
    管理好自己,才是一个人最大的本事
    ThreadLocal
    【深度学习】实验6布置:图像自然语言描述生成(让计算机“看图说话”)
    小程序 表单当用户修改字段,点击返回检测用户是否有修改
    2022年12月编程语言排行榜,数据来了!
  • 原文地址:https://blog.csdn.net/FMC_WBL/article/details/139909209
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号