2021年06月07日 周一 天气晴 【不悲叹过去,不荒废现在,不惧怕未来】
1. x为非负整数
1.1 返回整数
这时稍微简单点,用二分法即可,唯一需要注意的就是越界问题。
class Solution {
public:
int mySqrt(int x) {
if(x==0 || x==1) return x;
int l=1, r=x;
while(l<r){
int m=l+(r-l+1)/2; // l 从 1 开始,不然 r+1 可能会越界
if(m>x/m) r=m-1; // 这里写成 m*m>x 也可能会越界,所以写成 m>x/m
else if(m==x/m) return m;
else l=m;
}
return l;
}
};
1.2 返回浮点数
1.2.1 二分法(不保证正确)
返回浮点数的话,最好用double,精度高,而且不用担心越界。
注意:要搞清楚题意,是要求误差小于e,还是精确到小数点后几位。
我感觉这两种描述不一样,但是也找不出它们之间的关系。如果题目要求精确到小数点后几位,就按照误差小于e来计算吧!
精确到小数点后3位表示误差小于0.001?
2023.11.16 @如三月兮 误差小于0.001,表示小数点后三位是固定下来了,假设2.6768,676此时刚固定下来, 下一次迭代得到的数是2.6765,这两个数的误差是0.0003<0.001满足条件退出迭代,返回的是2.676,
这时只能说明小数点后3位固定是精确的,再往后迭代误差绝对小于0.001,但是第4位不固定
double my_sqrt(int x) {
if (x == 0 || x == 1) return x;
const double e = 1e-8;
double dx = x;
double l = 1., r = dx, m = l + (r - l) / 2.; // 这里要除以一个浮点数
while (fabs(m * m - dx) >= e) {
if (m * m - dx >= e) r = m - e;
else l = m + e;
m = l + (r - l) / 2.;
}
return m;
}
1.2.2 牛顿迭代法(推荐)
返回浮点数的话,最好还是用牛顿迭代法,收敛更快,而且准确性也高。
double mySqrt(int x) {
if (x == 0) return x;
const double e = 1e-8;
double C = x, x0 = x;
do {
x0 = 0.5 * (C / x0 + x0);
} while (fabs(x0 * x0 - x) >= e);
return x0;
}
2. x为浮点数
直接用牛顿迭代法吧。
double mySqrt(double x) {
if (x == 0.0) return x;
const double e = 1e-8;
double C = x, x0 = x;
do {
x0 = 0.5 * (C / x0 + x0);
} while (fabs(x0 * x0 - x) >= e);
return x0;
}
3. 总结
除了返回整数的,其它情况都推荐用牛顿迭代法!
参考文献
https://leetcode-cn.com/problems/sqrtx/solution/x-de-ping-fang-gen-by-leetcode-solution/