【算法】二分法(数的范围,数的三次方根)

二分法-数的范围

2021.11.4

单调性---->二分法(不一定要求单调)

找到一个性质,将数列一分为二,用二分法寻找边界

原数列为升序排列好的一组数。

注:本人认为,在解决数的范围这个问题上,传统二分法似乎不是最优解法

代码段注释:

 上方两个函数模板为通用二分法模板

主函数内的函数性质为寻找目标元素首次出现和末次出现的下标

寻找首次出现下标时,首先二分数列,划分定位到目标元素所在的区间段(即if中的判断元素是否大于目标元素)

因为要查找首次出现的下标,必然是先将右边界先赋值,主要查找“相对左边”的一个区间段。

注意到先给右边界赋值这个决定了使用第一模板mid的取值应该为 L+R,考虑到边际效应;

然后在if句不满足的时候,将左边界赋值 丢弃 一定不存在目标数的区间段。

最后当区间压缩为1的时候,则必然能找到一个数字(无论符不符合条件,二分法一定最后压缩出来一个结果,最后再进行性质判断)

然后再是查找末次出现下标,再次二分数列,这次主要查找“相对右边”的一个区间段,所以必然先给左边界赋值(这个左边界第一次赋值一定是第一次出现),不满足if条件时,将右边界赋值 丢弃一定不存在目标数的区间段,直到区间压缩为1,即是目标数。

这里的给左边界先赋值决定了使用第二模板即mid=L+R+1;

int bsearch1(int l, int r)
{
	while (l < r)
	{
		int mid = l + r >> 1;
		if (check(mid))r = mid;
		//check判断mid是否满足性质
		else l = mid + 1;
	}
	return l;
}

int bsearch2(int l,int r)
{
	while (l < r)
	{
		int mid = l + r+1 >> 1;
		if (check(mid)) l= mid;
		//check判断mid是否满足性质
		else r = mid - 1;
	}
	return l;
}
int main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	cin >> n >> m;
	for (int i = 0; i < n; i++)cin >> a[i];
	while (m--)
	{
		int x;
		cin >> x;
		int l = 0, r = n - 1;
		while (l < r)
		{
			int mid = l + r >> 1;
			if (a[mid] >= x)r = mid;
			else l = mid + 1;
		}
		if (a[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 (a[mid] <= x)l = mid;
				else r = mid - 1;

			}
			cout << l << endl;
		}
	}
}

二分法-数的三次方根

2021.11.05

给定一个浮点数,求它的三次方根,并保留6位小数

解析

判断性质为如果中间数的三次方大于x时,则将右边界缩小,所以采用第一个模板mid=r+l/2;

值得注意的是结果需要保留6位小数,这里需要使用一个printf库函数,默认保留小数点后6位

下面是printf的使用规则

int main()
{
	double x;
	cin >> x;
	double l = -10000, r = 10000;
	while (r - l > 1e-8)
	{
		double mid = (l + r) / 2;
		if (mid * mid * mid >= x)r = mid;
		else l = mid;
	}
	printf("%lf", l);
}

猜你喜欢

转载自blog.csdn.net/nathanqian123/article/details/121138629