Day17——T69.x的平方根
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
-
"笨蛋"做法,简单无脑易上手
/*循环找到乘方相等的值,返回*/ class Solution { public: int mySqrt(int x) { long a; for(long i = 0; i * i <= x; ++ i) { a = i; } return a; } };
-
袖珍计算器算法(取巧做法)
题干表明不能使用求根函数,可以转化为使用其他函数,完成计算
显然
根号x = x^1/2 = (elnx)1/2 = e^(1/2*lnx)
需要用到exp( )函数 和 log( )函数
注意: 由于计算机无法存储浮点数的精确值,而指数函数和对数函数的 参 数和返回值均为浮点数,因此运算过程中会存在误差。所以得到整数部分ans 后,应该找出ans 与 ans + 1哪个才是答案
class Solution {
public:
int mySqrt(int x) {
if(x == 0)
{
return 0;
}
int ans = exp(0.5 * log(x));
/*若ans + 1的平方小于等于x,刚好满足舍去小数部分的条件,返回ans + 1*/
/*若ans + 1的平方大于x,则说明ans + 1大了,应取ans*/
return ((long long) (ans + 1) * (ans + 1) <= x ? ans + 1 : ans);
}
};
-
二分查找(推荐)
class Solution { public: int mySqrt(int x) { int left = 0, right = x; while(left <= right) { // 闭区间 int mid = left + (right - left) / 2; if((long) mid * mid <= x) left = mid + 1; else right = mid - 1; } return left - 1; // 正平方根永远会在 left 左边一个的位置,所以写成 left - 1 即可 } };
-
牛顿迭代法(推荐)
牛顿迭代法的本质是借助泰勒级数,从初始值开始快速向零点逼近。我们任取一个x0作为初始值,在每一步的迭代中,我们找到函数图像上的点 (xi,f(xi)),过该点作一条斜率为该点导数 f ′(x i) 的直线,与横轴的交点记为 x (i+1)。x (i+1)相较于 x i 而言距离零点更近。在经过多次迭代后,我们就可以得到一个距离零点非常接近的交点。
y l = 2 x i ( x − x i ) + x i 2 − C = 2 x i x − ( x i 2 + C ) yl = 2xi(x - xi) + xi ^ 2 - C = 2xix - (xi ^ 2 + C) yl=2xi(x−xi)+xi2−C=2xix−(xi2+C)
当 y 等于 0 时,移项得 x ( i + 1 ) = 1 / 2 ( x i + C / x i ) 当y等于0时,移项得x(i+1) = 1/2 (xi + C/xi) 当y等于0时,移项得x(i+1)=1/2(xi+C/xi)
-
迭代结束的标志
每次迭代后,都会离零点更近,所以当相邻两次迭代所得交点非常接近时(差值是否小于一个极小的非负数,一般取10^-6 或 10^-7),可以断定,已经足够得到答案。
-
class Solution {
public:
int mySqrt(int x) {
if(x == 0)
{
return 0;
}
double C = x,x0 = x;
while(true)
{
double xi = 0.5 * (x0 + C / x0);
if(fabs(x0 - xi) < 1e-7)
{
break;/*迭代结束*/
}
x0 = xi;/*以本次迭代出的xi值作为下次迭代的初始值*/
}
return int(x0);
}
}