数据结构与算法课题目复盘笔记—一文搞懂求n次方根问题(吃透浮点数二分问题)

这里主要拿题目790. 数的三次方根作为例题进行讲解:

题目:790. 数的三次方根

题目描述:
给定一个浮点数 n,求它的三次方根。

输入格式
共一行,包含一个浮点数 n。

输出格式
共一行,包含一个浮点数,表示问题的解。

注意,结果保留 6 位小数。

数据范围
− 10000 ≤ n ≤ 10000 −10000≤n≤10000 10000n10000
输入样例:
1000.00 1000.00 1000.00
输出样例:
10.000000 10.000000 10.000000

本题重难点和思路

本题本质上就是浮点数二分的经典应用:

假设要二分的左边界为l, 右边界为r,要开方的数为a
由于没有取整问题,所以就不存在整数二分的边界 l 和 r 更新时是否要+1的问题,更新边界时直接令 l = mid 或者 r = mid就可以了,时时刻刻保证答案在区间 [l, r] 内部,当 (r - l) 的值小于一个很小的数时, 就可以用 l 当作我们的答案

浮点数二分的难点:

  1. 二分左右边界的初始化问题,如果和整数二分一样,无脑初始化为:
int l = 0, r = a;

这样是正确的吗?

答案是不正确! 因为要二分的数很有可能是个小数,比如计算0.001的三次方根,我们都知道是0.1,如果和整数二分一样直接取要开方的数作为右边界,这个时候我们想要的最终结果0.1是不在设定的二分区间[0, 0.001]之间的,这个时候再去二分一定是有问题的。而且更何况奇数次方根的输入可能是负数,所有这些问题都要考虑到!
正确的初始化方法是我们二分边界l 和 r 的绝对值大小不能全部小于1,至少有一个绝对值大于1,这里由于有负数的存在,所以简便起见,可以这样初始化:

double l = min(-1.0, a), r = max(1.0, a);

或者也可以无脑写

double l =10000, r = 10000;
  1. 惯性思维还把写 l = mid + 1或者 r = mid - 1;
    前面说过由于没有取整问题,所以就不存在整数二分的边界 l 和 r 更新时是否要+1的问题,更新边界时直接令 l = mid 或者 r = mid就可以了

  2. 关于输出结果保留几位小数的问题:
    printf默认保留6位小数,假如其他题目有其他特殊要求
    可以使用下面方法指定保留位数:
    比如我们想要保留9位小数:

printf("%.9lf",a); 保留小数点后9

C++代码

#include<iostream>
#include<algorithm>
using namespace std;

int main(){
    double a;
    cin >> a;  // scanf("%lf", &a);
    double l = min(-1.0, a), r = max(1.0, a);
    while(r - l > 1e-8) {
        double mid = (l + r) / 2;
        if(mid * mid * mid >= a) r = mid;
        else l = mid;
    }
    printf("%lf", l); //printf默认保留6位小数
    return 0;
}

总结

这道题是浮点数二分的经典问题,还是有很多细节需要注意的,这些问题只有实际写的时候才会发现,所以还是多动手写!

遇到n次方根问题(浮点数二分问题)只要按照上面的思路和代码模板,根据题目稍加改动就可以解决了!!!
欢迎大家关注本人公众号:编程复盘与思考随笔
(关注后可以免费获得本人在csdn发布的资源源码)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Al资料站与复盘笔记

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

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

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

打赏作者

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

抵扣说明:

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

余额充值