二分(整数二分 浮点数二分)

目录

一、整数二分

模板

右边界二分查找(左开右闭)

左边界二分查找(左闭右开)

应用

数的范围

二、浮点数的二分

模板

应用

算术平方根

三、习题

1.数的三次方根


一、整数二分

tip:满足单调性的数组一定可以使用二分查找,但可以使用二分查找的数组不一定需要满足单调性

假设我们找到了条件 C1,和它的对立条件 C2,就能够将数组a二分,如下图所示:

观察上图可以发现,索引3索引4这两个位置都可以作为 C1 和 C2 的分界点。其中,索引3是红色区域的右边界索引4是绿色区域的左边界。而我们接下来要讨论的二分查找模板就是用来寻找 C1 和 C2 的分界点的。

模板

右边界二分查找(左开右闭)

需注意l + r + 1的条件, 否则当l = r - 1时,会导致无限循环。

int right_bound(int l, int r) {
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

左边界二分查找(左闭右开)

int left_bound(int l, int r) {
    while (l < r) {
        int mid = (l + r) >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

应用

数的范围

tip:找好需要寻找的左边界和右边界。

建议通过区间图的方式,来决定求左边界还是右边界。

void Solution()
{
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 0; i < n; ++i) scanf("%d", &q[i]);
	while (m--)
	{
		int x, l = 0, r = n - 1;
		scanf("%d", &x);
		while (l < r)
		{
			int mid = (l + r) >> 1;
			if (q[mid] >= x) r = mid;
			else l = mid + 1;
		}
		if (q[l] != x) std::cout << "-1 -1" << std::endl;
		else
		{
			std::cout << l << ' ';

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

二、浮点数的二分

浮点数的二分法与整数二分法同理,但是可以不用注意边界问题。

模板

int bound(int l, int r) {
    while (r - l > 1e-6) {
        int mid = (l + r + 1) >> 1;
        if (check(mid)) l = mid;
        else r = mid;
    }
    return l;
}

应用

算术平方根

根据经验,保留小数点后几位数,就将循环条件中的极小数往减小2位。

例如:

保留6位小数,将 while (r - l > 1e-8) 中写为1e-8。

保留4位小数,将 while (r - l > 1e-6) 中写为1e-6。

void Solution2()
{
	double x;
	scanf("%lf", &x);
	double l = -1000.0, r = 1000.0;
	while (r - l > 1e-8)
	{
		double mid = (r + l) / 2;
		if (mid * mid >= x) r = mid;
		else l = mid;
	}
	std::cout << l << std::endl;
}

三、习题

1.数的三次方根

void Solution()
{
	double x;
	scanf("%lf", &x);
	double l = -1000.0, r = 1000.0;
	while (r - l > 1e-8)
	{
		double mid = (l + r) / 2.0;
		if (mid * mid * mid >= x) r = mid;
		else l = mid;
	}
	std::cout << l << std::endl;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值