来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sqrtx
实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
- 这是一道看似很简单的题,但是真正做起来又有点无从下手,查看题解才知道有多种解法。
- 第一种解法是利用内置函数的对数函数和指数函数去完成。由于根号x的另一种写法是x1/2,可以变形成e1/2lnx,这样的话利用前面提到的内置函数就能够解决这一题。
int mySqrt(int x){
if (x == 0)
return 0;
int ans = exp(0.5 * log(x));
return ((long long)(ans + 1) * (ans + 1) <= x ? ans + 1 : ans);
}
-
double exp(double x);返回e的x 次方计算结果。
double log (double x);返回以e为底的对数值。
由于指数函数和对数函数的返回值均为浮点数,但计算机无法存储浮点值的精确值,因此在运算过程中会存在误差,在得到结果值ans后还需要判断ans和ans+1哪个是真正的答案。 -
c语言中将一个浮点型赋值给整型时,不会四舍五入,会直接舍去小数部分的数据,也可以认为是执行了下取整运算。
-
在64位操作系统中,用8个字节来存储整型,int占4个字节,long占8个字节。
- 第二种解题方法是利用二分法, 由于给定的数值x的平方根的整数部分ans是满足ans2小于等于x的最大整数,因此可以利用二分法,将上界设置为0,下界设置为x,每次将中间的数值的平方与x进行对比,然后不断缩小范围,最后就能够解决该题目。
int mySqrt(int x){
int left = 0, right = x, ans = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if ((long long)mid * mid <= x) {
left = mid + 1;
ans = mid;
} else {
right = mid - 1;
}
}
return ans;
}
- 第三种题解方法是牛顿迭代法。牛顿迭代法是一种可以用来快速求解函数零点的方法。我们设f(x) = x2 - C,则根号C就是函数的零点,我们取一点作为初始值x0(这里取给定的值x),做切线与x轴相交,得到的交点比x0更加接近函数的零点根号C,将此次得到的交点赋值给x0,再次做切线与x轴相交,得到更加接近函数零点的一个交点。这样重复多次迭代,就能够得到一个十分接近函数零点的值了(一般两数差小于10-6或10-7就认为是相等)。
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;
}
return (int)x0;
}