二分(C++) 数的范围 三次方根

二分通常指的是二分查找(Binary Search),它是一种高效的查找算法,用于在有序数组中查找某一特定元素的位置。二分查找的思路是:

  1. 每次取中间位置的元素与目标值进行比较。
  2. 如果中间位置的元素正好等于目标值,则查找成功。
  3. 如果中间位置的元素大于目标值,则在数组的左半部分继续查找。
  4. 如果中间位置的元素小于目标值,则在数组的右半部分继续查找。
  5. 重复上述过程,直到找到目标值或查找范围为空。

一.数的范围

题目

给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。

对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。

如果数组中不存在该元素,则返回 -1 -1

代码

#include<iostream>
using namespace std;
const int N = 1e5 + 5;
int arr[N];
int n, q;
int main()
{
	int k = 0;
	scanf("%d%d", &n, &q);
	for (int i = 0; i < n; i++) scanf("%d", &arr[i]);
	while (q--)//循环q次
	{
		scanf("%d", &k);//查询的数
		int l = 0, r = n - 1;//首尾
		while (l < r)//l=r时停止
		{
			int mid = l + r >> 1;//中点
			if (arr[mid] >= k) r = mid;//中值>=k,缩小范围0到mid
			else l = mid + 1;//中值<=k,缩小范围mid+1到n-1
		}//以此类推求出左边界
		if (arr[l] != k)//如果剩下的一个不是k返回-1 -1
		{
			printf("-1 -1\n");
			continue;//结束本次循环
		}
		else printf("%d ", l);//是k,输出序号
		r = n - 1;
		while (l < r)
		{
			int mid = l + r + 1 >> 1;//加1向上取整,求左边界向下,求右边界向上对称
			if (arr[mid] <= k) l = mid;//对称
			else r = mid - 1;//对称
		}
		printf("%d\n", l);//输出右边界
	}
	return 0;
}

解析

while (l < r)//l=r时停止
{
	int mid = l + r >> 1;//中点
	if (arr[mid] >= k) r = mid;//中值>=k,缩小范围0到mid
	else l = mid + 1;//中值<=k,缩小范围mid+1到n-1
}//以此类推求出左边界

1.查找左边界,中点值与查找值比较然后缩小范围,中间值大右边界缩小到 mid,中间值左边界缩小到mid + 1,循环直到 l = r,

if (arr[l] != k)//如果剩下的一个不是k返回-1 -1
{
    printf("-1 -1\n");
	continue;//结束本次循环
}
else printf("%d ", l);//是k,输出序号

2.判断结束时对应的数是不是要查找的数,不是的话输出 -1 停止本次循环,是的话输出左边界 l

r = n - 1;
while (l < r)
{
	int mid = l + r + 1 >> 1;//加1向上取整,求左边界向下,求右边界向上对称
	if (arr[mid] <= k) l = mid;//对称
	else r = mid - 1;//对称
}

3.求右边界,更新 r,求左边界到末尾的右边界,求法与左边界类似,对称, l + r + 1 >> 1 向上取整,因为下一步 if 判断条件是 <=,到最后一步剩两个元素的时候向下取整会发生死循环,即

l+1=r
l<r
mid=l
q[mid]<=x
l=mid=l

二、三次方根

题目

给定一个浮点数 n,求它的三次方根。(-10000<n<10000)

代码

1.二分法
#include<iostream>
using namespace std;
int main()
{
    double x;
    scanf("%lf", &x);
    double l = -10000, r = 10000;
    while (r - l > 1e-8) //精度
    {
        double mid = (l + r) / 2;//取中点
        if (mid * mid * mid >= x) r = mid;//mid在右,替换r
        else l = mid;
    }
    printf("%lf\n", l);

    return 0;
}
2.牛顿迭代法
#include<iostream>
#include<cmath> //绝对值函数abs
using namespace std;
int main()
{
    double n;
    scanf("%lf", &n);
    double x = n, prev_t = x - 1;
    while (abs(x - prev_t) > 1e-8)//精度
    {
        prev_t = x;
        x = (2 * x * x * x + n) / (3 * x * x);//牛顿迭代
    }
    printf("%lf\n", x);
    return 0;
}

解析

1.二分法
double l = -10000, r = 10000;

n 的范围

while (r - l > 1e-8) //精度
{
    double mid = (l + r) / 2;//取中点
    if (mid * mid * mid >= x) r = mid;//mid在右,替换r
    else l = mid; 
}

循环条件 l 与 r 的差值大于10的-8次方,为所求值的精度,通过中点值的3次方与所开值比较所小范围,直到循环结束得到所求值

2.牛顿迭代法

根据迭代公式 

 x_{n+1}= x_{n}-\frac{f(x)}{f'{(x)}}

求解x^{3}-n=0 的根

x_{n+1}= x_{n}-\frac{x_{n}^{3}-n}{3x_{n}^{2}}

x_{n+1}= \frac{2x_{n}^{3}+n}{3x_{n}^{2}}

迭代求解即可

double x = n, prev_t = x - 1;

 设定两个变量分别储存迭代前和迭代后的结果,其中x可为任意正整数

while (abs(x - prev_t) > 1e-8)//精度
{
    prev_t = x;
    x = (2 * x * x * x + n) / (3 * x * x);//牛顿迭代
}

循环条件:迭代后的值-迭代前的值>10的-8次方

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值