题目描述:实现 int sqrt(int x) 函数。 计算并返回 x 的平方根,其中 x 是非负整数。 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,
由于返回类型是整数,小数部分将被舍去。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sqrtx
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
根据题意不可以使用Math库的sqrt函数,所以需要去研究该sqrt函数是怎么实现的
方法一:
二分法
假设x(非负整数)的平方根为sqrts,那么sqrts一定是在区间【1,,x】之间的数
算法思想
- 定义l=1,r=x,ans=0(结果值),进入循环while(l<=r)求得中位数mid=(r+l)/2;
- 如果mid的平方小于x,记录ans=mid,那么继续对区间【mid+1,r】处理,直到l>r结束
- 如果mid的平方大于x,那么继续对区间【l,mid-1】处理
- 如果mid的平方等于x,那么直接返回mid
如果x是一个可以直接开平方没有小数部分的数,例如,9,16,25,程序运行时最后会直接进入第四步,如果是一个15,,开平方有小数部分的,需要设置一个ans变量来记录变换区间时的值,当到3*3这一步时,9<15,所以ans=3,左区间加一为4,此时l>r,循环结束。
java代码实现
public int mySqrt(int x) {
int L = 1, R = x;
int ans = 0;
while (L <= R) {
int mid = (L + R) / 2;
int square = mid * mid;
if (square == x) {
return mid;
} else if (square < x) {
ans = mid; //存起来以便返回
L = mid + 1;
} else {
R = mid - 1;
}
}
return ans;
}
如果x = Integer.MAX_VALUE 的话,下边两句代码是会溢出的。
int mid = (L + R) / 2;
int square = mid * mid;
所以建议使用long变量,
使用long类型变量,注意返回时,要强制转型为int返回
class Solution{
public int mySqrt(int x) {
long L = 1, R = (long)x;
long ans = 0;
while (L <= R) {
long mid = (L + R) / 2;
long square = mid * mid;
if (square == x) {
return (int)mid;
} else if (square < x) {
ans = mid; //存起来以便返回
L = mid + 1;
} else {
R = mid - 1;
}
}
return (int)ans;
}
}
也可以不使用long变量
int mid = L + (R - L) / 2;等价于 int mid = (L + R) / 2;
只不过前者不会溢出数据类型
int div = x / mid;
如果修改为这句,那么if语句以及else if中的条件判断也需要进行修改
if(div==mid)
return mid;
。。。。。。
方法二:
牛顿法
牛顿迭代法是一种可以用来快速求解函数零点的方法,用n表示待求出平方根的那个整数,那么n的平方根就是函数f(xn)=x^2-n的零点,利用牛顿迭代通式(无限逼近零点)可得
java代码实现:
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);
//x0和xi都是x^2-n=0的近似零点解,但是需要的解的要求是:求出的前后的两个解的差很小才能满足程序的输出要求
if(Math.abs(x0-xi)<1e-7){
break;
}
x0=xi;
}
return (int)x0;
}
}
另一种思考角度利用牛顿迭代法也可以解决
class Solution{
public int mySqrt(int n) {
double t = n; // 赋一个初值
//直到找到一个解x=t满足,函数x^2-n<=0.1
while (Math.abs(t * t - n) > 0.1) {
t = (n / t + t) / 2.0;
}
//先对t进行四舍五入
int ans = (int) Math.round(t);
//判断ans^2是否超出n
if ((long) ans * ans > n) {
//超出了ans-1就是答案,ans自减
ans--;
}
return ans;
}
}