LeetCode-34. Search for a Range

本文介绍了一种在有序整数数组中查找指定目标值起始和结束位置的方法。通过两种不同的算法实现,即两指针法和二分查找法,并详细解释了它们的工作原理及优劣对比。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given an array of integers sorted in ascending order, find the starting and ending position of a given target value.

Your algorithm’s runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].

方法一:两指针法

思路:
  1. 一个指针从数组头开始遍历,一旦找到目标值后就将其下标保存到输出数组中。
  2. 另一个指针从数组尾开始遍历,一旦找到目标值后就将其下包保存到输出数组中。
细节:
  1. 可以先将输出数组初始化成[-1,-1],当第一遍遍历完成后,如果数组数值仍然是[-1,-1],则说明数组中不包含目标值,也就不需要第二次遍历了,直接返回输出数组。
  2. 时间复杂度O(n),所以此方法不满足题目要求的时间复杂度,但官网上可以通过。
  3. 空间复杂度:O(1)。
C++实现
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> res(2,-1);
        for(int i=0;i<nums.size();++i)
        {
            if(nums[i]==target)
            {
                res[0]=i;
                break;
            }
        }
        if(res[0]==-1)
            return res;
        for(int i=nums.size()-1;i>=0;--i)
        {
            if(nums[i]==target)
            {
                res[1]=i;
                break;
            }
        }
        return res;
    }
};

方法二:二分查找

思路:使用改进的二分查找分别寻找区间的两个端点。
步骤:

  1. 首先定义两个指针分别指向数组的头与尾。
  2. 寻找左端点:如果数组的中间值大于或者等于目标值时,说明左端点位于数组的左边(包括中间值),所以我们就将右指针移到当前数组的中间位置,继续查找;如果数组的中间值小于目标值,说明左端点位于数组的右边,我们就将左指针移到当前数组的中间位置的下一位置上,继续查找。
  3. 以这种方式搜索完成后,左指针就指向了左端点。我们需要注意到一些边界情况:当左指针超过数组下标范围,或者左指针就没移动过时,我们需要对此进行判断该数组中是否存在目标值,如果没有则直接返回输出数组。
  4. 寻找右端点:这里有两种方法。第一种方法就是在前面搜索的基础上,再在剩下的右半段中寻找右端点,我们需要使用一个技巧,让中间端点为mid=(lo+hi)/2+1;,这样就不影响循环,思想和寻找左端点差不多。
    另一种是只要当数组中间值不大于目标值时就将左指针指向中间的下一位,注意最后要将左指针减1,所以需要先将右指针指向数组末尾的下一位。

时间复杂度:O(log n);空间复杂度:O(1)。

Java实现
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res={-1,-1};
        int lo=0,hi=nums.length-1;
        //求区间左端点       
        while(lo<hi)
        {
            int mid=(lo+hi)/2;
            if(nums[mid]>=target)
                hi=mid;
            else
                lo=mid+1;
        }
        if(lo==nums.length||nums[lo]!=target)
            return res;
        res[0]=lo;
        //求区间右端点
        hi=nums.length-1;
        while(lo<hi)
        {
            int mid=(lo+hi)/2+1;
            if(nums[mid]>target)
                hi=mid-1;
            else
                lo=mid;
        }
        res[1]=lo;
        return res;
    }
}
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res={-1,-1};
        int lo=0,hi=nums.length-1;
        //求区间左端点       
        while(lo<hi)
        {
            int mid=(lo+hi)/2;
            if(nums[mid]>=target)
                hi=mid;
            else
                lo=mid+1;
        }
        if(lo==nums.length||nums[lo]!=target)
            return res;
        res[0]=lo;
        //求区间右端点
        lo=0;
        hi=nums.length;
        while(lo<hi)
        {
            int mid=(lo+hi)/2;
            if(nums[mid]>target)
                hi=mid;
            else
                lo=mid+1;
        }
        res[1]=lo-1;
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值