前言
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
示例 1:
输入:x = 4
输出:2
示例 2:
输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842…, 由于返回类型是整数,小数部分将被舍去。
一、二分法
1.1
二分法不做赘述,代码如下:
// 二分法
int mySqrt(int x){
int index = -1; // 因为 0/1都可能是结果,所以 -1 用来表示不可能的结果
int left = 0, right = x;
long mid;
while(left <= right)
{
mid = left + (right - left)/2;
if(mid * mid <= x) // 此处 mid*mid的类型是int,可能会导致溢出。所以mid的类型要为long
{
index = mid;
left = mid + 1;
}
else
{
right = mid - 1;
}
}
return index;
}
二、牛顿迭代法
2.1
假设平方根是 i,则 i 和 x/i 必然都是 x 的因子,而 x/i 必然等于 i,推导出 i + x/i = 2 * i,得出 i = (i + x/i) / 2。
由此得出解法,i 可以任选一个值,主要上述公式成立,i 必然是 x 的平方根,如果不成立,(i + x/i) / 2得出的值进行递归,直至得出正确解。
为什么“(i + x/i) / 2得出的值进行递归,就能得出正确解”?
假设求 12 的平方根,我们令 i 等于12。这样的话,(i + x/i) / 2 = (12 + 12/12)/ 2 = 13 / 2 = 6.5,c语言中对 6.5 类型转换为 int,结果就是 6。此时,6 相比 12(i)和 1(12/12)更接近 12 的平方根。
接着把 6 赋值给 i,得到 (i + x/i) / 2 = (6 + 12/6)/ 2 = 8 / 2 = 4。此时,4 相比 6(i)和 2(12/6)更接近 12 的平方根(2 的平方是 4,6 的平方是 36,而 4 的平方是 16,最接近 12)。即两个因子的均值更接近其平方根。
最终代码如下:
// 牛顿迭代法
double squart(double i, int x)
{
double res = (i + x/i)/2; // res 比 i 更接近 x 的平方根
if(res == i)
{
return i;
}
else
{
return squart(res, x);
}
}
int mySqrt(int x){
if(x == 0 || x == 1) return x;
return (int)squart(x, x); // x的取值只会影响计算次数,取什么值无所谓。
}