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

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



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

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

进阶:

你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?

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



思路:


方法1 :遍历数组,记录目标值出现的第一次和最后一次的位置。

O(N)的时间复杂度无法通过这题,没有用到数组有序的条件,可以使用二分求解。



方法2


假设给定数组 nums = [5,7,8,8,9,10,10] ,target = 8


需要求目标值在数组中第一次和最后一次出现的位置。


如果是正常的二分查找,此时遇到目标值就返回。我们需要先找到target第一次出现的位置。

在这里插入图片描述

寻找左边界:


此时设置判断条件为 target <= nums[mid],

当nums[right] == num[mid] 时不返回,继续在左区间寻找。


代码示例:

//求目标值左边界
int lowbound(int* nums, int numsSize, int target)
{   
    int left  = 0;
    int right = numsSize - 1;
	
    while(left <= right)
    {
        int mid = left + (right - left);
       	//找到target时不返回,继续在左区间查找。
        if(target <= nums[mid])
        {
            right = mid - 1;
        }
        else if(target > nums[mid])
        {
            left = mid + 1;
        }
    }
    //循环结束left位于左边界
    return left;
}

过程图示

在这里插入图片描述
当循环结束时,left位于目标值左边界。

在这里插入图片描述

寻找右边界:


和寻找左边界相反,如果寻找target时,继续往右区间寻找。

target >= nums[mid]

int highbound(int* nums, int numsSize, int target)
{
    int left  = 0;
    int right = numsSize - 1;

    while(left <= right)
    {
        int mid = left + (right - left);
        if(target < nums[mid])
        {
            right = mid - 1;
        }
        //继续往右区间查找。
        else if(target >= nums[mid])
        {
            left = mid + 1;
        }   
    }
    //循环结束right位于右边界
    return right;
}

搜索过程:


循环停止时,right 停留在下边界。

在这里插入图片描述


总体:

int* searchRange(int* nums, int numsSize, int target, int* returnSize)
{
    if(nums == NULL)    return NULL;

   int left = lowbound(nums,numsSize,target);//求左边界
   int right = highbound(nums,numsSize,target);//求右边界

    int* retArr = (int*)malloc(sizeof(int) * 2);
    *returnSize = 2;
    
    //left>right时,说明找不到目标值
    if(left > right)
    {
        retArr[0] = -1;
        retArr[1] = -1;
        return retArr;
    }
    retArr[0] = left;
    retArr[1] = right;
    
    return retArr;
}


int lowbound(int* nums, int numsSize, int target)
{   
    int left  = 0;
    int right = numsSize - 1;

    while(left <= right)
    {
        int mid = left + (right - left);
        if(target <= nums[mid])
        {
            right = mid - 1;
        }
        else if(target > nums[mid])
        {
            left = mid + 1;
        }
        
    }
    return left;
}

int highbound(int* nums, int numsSize, int target)
{
    int left  = 0;
    int right = numsSize - 1;

    while(left <= right)
    {
        int mid = left + (right - left);
        if(target < nums[mid])
        {
            right = mid - 1;
        }
        else if(target >= nums[mid])
        {
            left = mid + 1;
        }   
    }
    return right;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

necesse

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

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

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

打赏作者

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

抵扣说明:

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

余额充值