[Algorithm][二分查找][在排序数组中查找元素的第一个和最后一个位置][x 的平方根]详细讲解


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

1.题目链接


2.算法原理详解

1.查找区间左端点

  • 令中间值为x,目标值为t
  • 如何迭代?
    • x < t -> left = mid + 1 -> [left, right]
    • x >= t -> right = mid -> [left, right]
  • 细节处理:
    • 循环条件left < right
    • 求中点方式left + (right - left) / 2 -> 向下取整
  • 循环条件为什么不能包含left == right
    • left == right的时候,就是最终结果,无需判断
    • 如果判断,就会陷入死循环
      • 如果最后一次判断条件为x < t -> left = mid + 1 -> [left, right]
        • 则没问题,正常结束
      • 如果最后一次判断条件为x >= t -> right = mid -> [left, right]
        • 则会一直right = mid,陷入死循环
  • 求中点方式为什么是left + (right - left) / 2
    • 偶数时:求的是左端点
    • 如果最后一次判断条件为x < t -> left = mid + 1 -> [left, right]
      • 则没问题,正常结束
    • 如果最后一次判断条件为x >= t -> right = mid -> [left, right]
      • 则会一直right = mid,陷入死循环
        ![[Pasted image 20240327221405.png]]

2.查找区间右端点

  • 令中间值为x,目标值为t
  • 如何迭代?
    • x <= t -> left = mid -> [left, right]
    • x > t -> right = mid - 1 -> [left, right]
  • 细节处理:
    • 循环条件left < right
    • 求中点方式left + (right - left + 1) / 2 -> 向上取整
  • 循环条件为什么不能包含left == right
    • left == right的时候,就是最终结果,无需判断
    • 如果判断,就会陷入死循环
      • 如果最后一次判断条件为x > t -> right = mid - 1 -> [left, right]
        • 则没问题,正常结束
      • 如果最后一次判断条件为x <= t -> left = mid -> [left, right]
        • 则会一直left = mid,陷入死循环
  • 求中点方式为什么是left + (right - left + 1) / 2
    • 偶数时:求的是右端点
    • 如果最后一次判断条件为x > t -> right = mid - 1 -> [left, right]
      • 则没问题,正常结束
    • 如果最后一次判断条件为x <= t -> left = mid -> [left, right]
      • 则会一直left = mid,陷入死循环
        请添加图片描述

3.代码实现

vector<int> searchRange(vector<int>& nums, int target) 
{
    // 处理边界情况
    if(nums.size() == 0)
    {
        return {-1, -1};
    }

    // 二分左端点
    int left = 0, right = nums.size() - 1;
    while(left < right)
    {
        int mid = left + (right - left) / 2;
        if(nums[mid] < target)
        {
            left = mid + 1;
        }
        else
        {
            right = mid;
        }
    }

    int begin = 0;
    if(nums[left] == target)
    {
        begin = left; // 标记左端点
    }
    else
    {
        return {-1, -1};
    }

    // 二分右端点
    // 这里其实left可以不做处理,算一个小优化
    left = 0, right = nums.size() - 1;
    while(left < right)
    {
        int mid = left + (right - left + 1) / 2;
        if(nums[mid] <= target)
        {
            left = mid;
        }
        else
        {
            right = mid - 1;;
        }
    }

    return {begin, right};
}

2.x 的平方根

1.题目链接


2.算法原理详解

  • 本题虽然可以直接遍历求值,但是时间复杂度为O(N),显然效率不高
  • 可以把问题抽象成,在数组 [ 1 , x ] [1, x] [1,x]内,找x的平方根
    • 此时,数组具有二段性,可以用二分查找
      请添加图片描述

3.代码实现

int MySqrt(int x) 
{
    // 处理边界情况
    if(x < 1)
    {
        return 0;
    }

    int left = 1, right = x;
    while(left < right)
    {
        long long mid = left + (right - left + 1) / 2;
        if(mid * mid <= x)
        {
            left = mid;
        }
        else
        {
            right = mid - 1;
        }
    }

    return left;
}
  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

DieSnowK

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

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

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

打赏作者

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

抵扣说明:

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

余额充值