3.二分查找

本文详细介绍了二分查找算法的实现步骤和关键点,并提供了两个具体的应用案例:AcWing789.数的范围和AcWing790.数的三次方根。在数的范围内查找目标值的起始和终止位置,以及计算数的精确三次方根。通过递归和迭代,实现了高效查找。

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

算法功能

查找有序数组中的某个元素的下标

输入输出

输入输出
最左元素下标:l目标元素的下标:l
最右元素下标:r
数组:a[]

算法步骤

  • 红色区域的右边界值
    在这里插入图片描述
  1. 找中间值 mid = (l+r+1)/2
int mid = l + r + 1 >> 1;//如果不加上1,那么mid得到的是下取整的数
//那么有可能[m,r]更新过后m会一直等于m(m+1==r的情况)会陷入死循环。
  1. 检查mid是不是在红色区间更新l或者r
 if (check(mid)) l = mid;//如果mid在红色区间,说明红色区域的右边界在mid的右边,更新l
        else r = mid - 1;//如果mid在绿色区间,说明红色区域的右边界在mid的左边,更新r
  1. 不断递归,直到递归到l==r
 int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}
  • 绿色区域的左边界值
    在这里插入图片描述
  1. 找中间值 mid = (l+r)/2
int mid = l + r >> 1;
  1. 检查mid是不是在绿色区间更新r或者l
 if (check(mid)) r = mid;//如果mid在绿色区间,说明绿色区域的右边界在mid的左边,更新r
        else l = mid + 1;
  1. 不断递归,直到递归到l==r
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

关键点

左区域的右边界—>l=mid, r=mid-1, mid = l + r + 1 >> 1
右区域的左边界—>r=mid, l=mid+1, mid = l + r >> 1


案例一:AcWing 789. 数的范围

AcWing 789. 数的范围

输入输出

输入输出
给定数组输出目标值起始位置和终止位置,没有返回[-1,-1]
给定查询目标值

步骤

  1. 给定数组
    scanf("%d%d", &n, &m);//n是待输入数组元素的个数,m是待输入目标值的个数
    for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);//输入数组
  1. 给定查询目标值
	int x;
	scanf("%d", &x);
  1. 查找目标值的起始位置
int l = 0, r = n - 1;
        while (l < r)
        {
            int mid = l + r >> 1;
            if (q[mid] >= x) r = mid;
            else l = mid + 1;
        }
  1. 判断目标值在数组中是否存在,如果不存在则返回"-1 -1"
if (q[l] != x) cout << "-1 -1" << endl;
  1. 如果存在,则查找目标值的末位置
int l = 0, r = n - 1;
            while (l < r)
            {
                int mid = l + r + 1 >> 1;
                if (q[mid] <= x) l = mid;
                else r = mid - 1;
            }

            cout << l << endl;
  1. 查询m遍
#include <iostream>

using namespace std;

const int N = 100010;

int n, m;
int q[N];

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);

    while (m -- )
    {
        int x;
        scanf("%d", &x);

        int l = 0, r = n - 1;
        while (l < r)
        {
            int mid = l + r >> 1;
            if (q[mid] >= x) r = mid;
            else l = mid + 1;
        }

        if (q[l] != x) cout << "-1 -1" << endl;
        else
        {
            cout << l << ' ';

            int l = 0, r = n - 1;
            while (l < r)
            {
                int mid = l + r + 1 >> 1;
                if (q[mid] <= x) l = mid;
                else r = mid - 1;
            }

            cout << l << endl;
        }
    }

    return 0;
}

案例二:AcWing 790. 数的三次方根

AcWing 790. 数的三次方根

输入输出

输入输出
一个数这个数的三次方根(保留 6 位小数)

步骤

  1. 给定待开根的数
	double x;
    cin >> x;
  1. 用二分查找法寻找
double l = -100, r = 100;
    while (r - l > 1e-8)//保留六位小数,经验一般是+2
    {
        double mid = (l + r) / 2;//明确中间值
        if (mid * mid * mid >= x) r = mid;
        else l = mid;//浮点型不用+1或者是-1
    }
  1. 输出三次方根
#include <iostream>

using namespace std;

int main()
{
    double x;
    cin >> x;

    double l = -100, r = 100;
    while (r - l > 1e-8)
    {
        double mid = (l + r) / 2;
        if (mid * mid * mid >= x) r = mid;
        else l = mid;
    }

    printf("%.6lf\n", l);//最好用printf,因为cout默认两位小数
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值