每日一题—— 在排序数组中查找元素的第一个和最后一个位置

每日一题

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

题目链接

在这里插入图片描述

思路

  • 看到这是一个非递减顺序排序的整数数组,且题目要求的时间复杂度为O(logn),我们可以知道,这题要用二分查找

  • 但这题不是简单的找到目标元素target就行了,而是要给出它在数组中的开始位置和结束位置。而我们知道·,如果一个数再一个有序数组中重复出现,那么如果使用二分查找,查找到的元素下标是不确定的(可能是第一个,可能是中间的,可能是最后一个)

  • 因此我们就需要对二分查找算法进行处理,找到target的开始位置left,结束位置right

    • 我们知道,普通二分法找到的条件是nums[mid]=target,如下图:
      在这里插入图片描述

    • 那么,如果我们当nums[mid]=target时不退出循环而是继续进行呢?

    • 假设我们要找结束位置right:显然结束位置应该在mid或mid右边的位置,那么我们就应该继续向右检索,怎么向右检索呢?我们知道二分查找中,当nums[mid]<target时,left就等于mid+1,mid自然也就右移了,这样不就实现了向右检索吗?如下图:

      在这里插入图片描述

    • 假设我们要找开始位置left:同样,开始位置应该在mid或mid左边的位置,所以当nums[mid] >= target时,right就等于mid-1,这样也就实现了mid的左移。如下图:

      在这里插入图片描述

实现代码

方法一
//找到开始位置下标
int leftRange(int *nums,int numsSize,int target)
{
    int left = 0;
    int right = numsSize - 1;
    int range;
    while(left <= right)
    {
        int mid = (right - left) / 2 + left;	//防止加法发生整形溢出
        if(nums[mid] >= target)		//只要mid的左边有target元素,就向左检索
        {
            right = mid - 1;
            range = right;		//存储可能成为开始位置的下标
        }
        else
            left = mid + 1;
    }
    return range+1;		//最后一次right=mid-1使得left>right,可以认为这是一个无效运算,因此需要将-1抵消
}    
//找到结束位置下标
int rightRange(int *nums,int numsSize,int target)
{
    int left = 0;
    int right = numsSize - 1;
    int range;
    while(left <= right)
    {
        int mid = (right - left) / 2 + left;
        if(nums[mid] > target)
            right = mid - 1;
        else		//只要mid的右边有target元素,就向右检索
        {
            left = mid + 1;  
            range = left;
        }
    }
    return range-1;	//最后一次left=mid+1使得left>right,可以认为这是一个无效运算,因此需要将1抵消
}
int* searchRange(int* nums, int numsSize, int target, int* returnSize){
    *returnSize = 2;
    int *number = (int *)malloc(sizeof(int) * (*returnSize));
    int left = 0;
    int right = numsSize - 1;
    int flag = 0;
    while(left <= right)		//首先判断target是否存在于数组中
    {
        int mid = (right - left) / 2 + left;
        if(nums[mid] < target)
            left = mid + 1;
        else if(nums[mid] > target)
            right = mid - 1;
        else
        {
            flag = 1;
            break;
        }
    }
    if(flag)	//如果存在
    {
        number[0] = leftRange(nums,numsSize,target);
        number[1] = rightRange(nums,numsSize,target);
    }
    else	//如果不存在
        number[0] = number[1] = -1;
    return number;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Forward♞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值