一般使用两种方法,二分法和牛顿迭代法
一般会让有两种求解结果,一种是求解其整数部分,另一种是求解浮点数并给出精度
二分法
思路
x的平方根的整数部分肯定是在0~x之间的,所以我们可以直接将其转换为在以0开头的有序数组中使用二分查找定位该数字(这数值就是mid:每次二分查找的中间值),那么mid^2一定是最接近x的。
需要定义的变量
l :表示左边值
r:表示右边值
mid:临时存储 l+r /2的中间值
n值的临界条件判断
当mid * mid > x,则 mid 取 l 到 mid -1的中间数,继续循环,直到mid * mid < x,mid就是要找的数 ;
当mid * mid <= x ,则mid取 mid +1 到 r 的中间数,并将mid 赋值给n ,直到两边界限重合,n就是要找的数。
时间复杂度:O(logN)
劣势:数值太大容易超过限制,可以做下修改
将临界的判断条件改成
mid > x / mid,则 mid 取 l 到 mid -1的中间数,继续循环,直到mid < x / mid,mid就是要找的数
当mid <= x / mid ,则mid取 mid +1 到 r 的中间数,并将mid 赋值给n ,直到两边界限重合,n就是要找的数。
//整数二分
//边界划分[l, mid - 1] [mid, r]
int bsqrt(int x)
{
if(x == 0||x == 1) return x;
int r = x;
int mid = 0;
int l = 0;
while(l < r)
{
mid = (int)(l/2.0 + r/2.0 + 0.5);//防止超出int范围
if(mid <= x / mid) l = mid;
else r = mid - 1;
}
return l;
}
直接浮点数求解二分开根号,注意设置精度
//使用浮点数二分
double bsqrt(double x)
{
const double esp = 1e-6;//精度
double r = x, l = 0.0;
while(r - l > esp)
{
double mid = r / 2.0 + l / 2.0;//防止超出范围
if(mid - x / mid >= esp) r = mid;//防止超出范围
else l = mid;
}
return l;
}
牛顿迭代法
求n的平方根,即计算
x
2
=
n
x^{2}= n
x2=n的解,令
f
(
x
)
=
x
2
−
n
f(x)=x^{2}-n
f(x)=x2−n,相当于求解
f
(
x
)
=
0
f(x)=0
f(x)=0的解。
1.首先取猜测
x
0
x_0
x0(例如可以设初次猜测值为
x
/
2
x/2
x/2),如果x_0不是解,做一个经过(x0,f(x0))这个点的切线,与
x
x
x轴的交点为
x
1
x_1
x1。 同理,如果
x
1
x_1
x1不是解,做一个经过
(
x
1
,
f
(
x
1
)
)
(x_1,f(x_1))
(x1,f(x1))这个点的切线,与x轴的交点为
x
2
x_2
x2。 以此类推。 以这样的方式得到的xi会无限趋近于f(x)=0的解。
2.判断
x
i
x_i
xi是否是
f
(
x
)
=
0
f(x)=0
f(x)=0的解有两种方法: 第一种是直接计算
f
(
x
i
)
f(x_i)
f(xi)的值判断是否为0,第二种是判断前后解
x
i
x_i
xi和
x
i
−
1
x_{i-1}
xi−1是否无限接近(误差精度)。经过
(
x
i
,
f
(
x
i
)
)
(x_i, f(x_i))
(xi,f(xi))这个点的切线方程为
f
(
x
)
=
f
′
(
x
i
)
(
x
−
x
i
)
+
f
(
x
i
)
f(x) = f'(x_i)(x - x_i)+f(x_i)
f(x)=f′(xi)(x−xi)+f(xi) ,其中
f
′
(
x
)
f'(x)
f′(x)为
f
(
x
)
f(x)
f(x)的导数。(本例中为
2
x
2x
2x)令切线方程等于0,即可求出
x
(
i
+
1
)
=
x
i
−
f
(
x
i
)
/
f
′
(
x
i
)
x(i+1)=x_i - f(x_i) / f'(x_i)
x(i+1)=xi−f(xi)/f′(xi)。在此题中,化简可得到迭代公式
x
i
+
1
=
x
i
−
(
x
i
2
−
n
)
/
(
2
x
i
)
x_{i+1}=x_i - (x_i^{2} - n) / (2x_i)
xi+1=xi−(xi2−n)/(2xi)
整数部分
#define error 1e-9//误差精度
class Solution {
public:
//inline double df(int& x, double& x0){return x0 - (x0 * x0 - x)/(2 * x0);}//化简一下(x0 + x / x0) / 2
inline double df(int& x, double& x0){return (x0 + x/ x0) / 2;}
int mySqrt(int x)
{
if(x == 0 || x == 1) return x;
double x0 = x / 2.0;
double x1 = df(x, x0);
while (abs(x0 - x1) >= error)
{
x0 = x1;
x1 = df(x, x0);
}
return (int) x1;
}
};
化简下
class Solution {
public:
int mySqrt(int x) {
if(x == 0 || x == 1) return x;
long res = x;
while (res * res > x)
{
res = (res + x / res) / 2;
}
return res;
}
};
返回浮点数
#define error 1e-9//误差精度
class Solution {
public:
//inline double df(int& x, double& x0){return x0 - (x0 * x0 - x)/(2 * x0);}//化简一下x0/2 + x/ (2x0)
inline double df(int& x, double& x0){return (x0 + x/ x0) / 2;}
double mySqrt(int x)
{
if(x == 0 || x == 1) return x;
double x0 = x / 2.0;
double x1 = df(x, x0);
while (abs(x0 - x1) >= error)
{
x0 = x1;
x1 = df(x, x0);
}
return x1;
}
};