• 力扣算法题:34、在排序数组中查找元素的第一个和最后一个位置.java版


    版本说明

    当前版本号[20230930]。

    版本修改说明
    20230930初版

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

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

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

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

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

    示例 1:

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

    示例 2:

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

    示例 3:

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

    提示:

    • 0 <= nums.length <= 105
    • -109 <= nums[i] <= 109
    • nums 是一个非递减数组
    • -109 <= target <= 109

    思路

    可以点击此篇博客看二分查找算法相关的图解:究竟是什么样的讲解二分查找算法的博客让我写了三小时???

    ​ 首先,我们可以用二分查找找到目标值 target 在数组中的任意一个位置 mid。若数组中不存在目标值,二分查找会返回不重复的插入位置,我们可以将开始位置和结束位置都设为 -1

    ​ 接下来,我们可以分别向左边和右边进行二分查找,以找到目标值在数组中的开始位置和结束位置。

    ​ 向左边查找时,我们不断将右边界设为 mid-1,直到找到排在 mid 前面的目标值或者边界越界。若找到目标值,我们将开始位置设为此位置,否则开始位置将保持为初始值 -1

    ​ 向右边查找时,我们不断将左边界设为 mid+1,直到找到排在 mid 后面的目标值或者边界越界。若找到目标值,我们将结束位置设为此位置,否则结束位置将保持为初始值 -1

    ​ 最后,我们返回开始位置和结束位置即可。

    返回的新数组左边的值是原先数组最左边的目标值:所以使用左寻找方法要再 j = m - 1; 确保这个值是最左边的

    右边的值是原先数组最右边的目标值:所以使用左寻找方法要再 i = m + 1; 确保这个值是最右边的

    代码

    class Solution
    {
        public int[] searchRange(int[] a , int target) {
            int k = left(a , target);
            if(k == -1)
            {
                return new int[]{-1,-1};
            }
            else
            {
                return new int[]{k , right(a, target)};
            }
    
        }
    
        public int left(int[] a , int target)
        {
            int i = 0;
            int j = a.length - 1 ;
            int candidate = -1 ; //待定值
            while (i <= j)
            {
                int m = (i+j) >>> 1;
                if(target < a[m])
                {
                    j = m - 1;
                }
                else if(a[m] < target)
                {
                    i = m + 1;
                }
                else
                {
                    candidate = m;
                    j = m - 1;   //继续向左走
                }
            }
            return candidate;
        }
    
        public int right(int[] a , int target)
        {
            int i = 0;
            int j = a.length - 1 ;
            int candidate = -1 ; //待定值
            while (i <= j)
            {
                int m = (i+j) >>> 1;
                if(target < a[m])
                {
                    j = m - 1;
                }
                else if(a[m] < target)
                {
                    i = m + 1;
                }
                else
                {
                    candidate = m;
                    i = m + 1;  //继续向右走
                }
            }
            return candidate;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    总结

    ​ 这段代码目的是查找一个按非递减顺序排列的整数数组中某个目标值的起始位置和结束位置。

    ​ 该函数采用了二分查找的算法思想,实现了一个函数 searchRange,用来实现时间复杂度为 O(log n) 的查找效率。具体来说,它通过调用 left 函数找到目标值在数组中的起始位置,然后再调用 right 函数找到目标值在数组中的结束位置。

    left 函数是一个二分查找算法的实现,它将数组分为两部分,通过不断更新起始位置和结束位置的指针,来逼近目标值的起始位置。每次循环中,它先计算中间位置 m,然后比较目标值与 a[m] 的大小,根据结果更新指针。如果目标值等于 a[m],则更新一个候选位置 candidatem,然后继续向左走以找到起始位置。最后,返回候选位置作为结果。

    right 函数同样是一个二分查找算法的实现,它与 left 函数类似,只是在查找目标值的结束位置时,向右走以逼近结束位置。

    ​ 总体而言,这段代码通过两次二分查找操作,高效地找到了目标值在数组中的起始位置和结束位置。它的时间复杂度为 O(log n),适用于大规模数据的查找。使用二分查找的思想,可以快速定位目标值并获取起始位置和结束位置的结果。

  • 相关阅读:
    解决 sh 和 bash 在执行脚本时的差异:双括号问题
    研究03丨ahr999屯币指数逐行代码深度剖析
    Kubernetes包管理工具-Helm3使用
    鸿鹄工程项目管理系统em Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统
    超实用!win10网页录屏的3种方法
    nginx服务和uwsgi服务如何设置开机自启动
    计算机组成原理-第六章 总线【期末复习|考研复习】
    秩序的美——队列的基础实现
    【unity】网格描边方法
    深度学习入门
  • 原文地址:https://blog.csdn.net/weixin_65106708/article/details/133442164