这是一道很简单的题目,就是求某个整型数字的平方根,题面如下:
这道题不难,首先最基本的可以使用迭代法来一个一个地尝试,但是这样的复杂度显然是O(n),属于所有算法中较差的一种。进阶一些的做法就是二分法来求解平方根,这样可以将算法的复杂度减小到O(
log
n
\log{n}
logn),但是要注意数据类型的位长,代码如下:
// search x's sqrt in inteval [Low, High)
long searchSqrt(int x, int Low, int High)
{
if(Low == High) // inteval is empty
{
if((long)Low * Low <= x)
return Low;
else
return Low - 1;
}
long Mid = ((long)Low + High) >> 1;
if(Mid * Mid == x)
return Mid;
else if(Mid * Mid > x)
return searchSqrt(x, Low, Mid);
else // Mid * Mid < x
return searchSqrt(x, Mid + 1, High);
}
写这篇文章的目的在于记录一种新的求解算法——牛顿梯度下降法
这个方法的好处不仅在于求解效率足够高,而且还有一个好处在于——我们可以控制解的精度范围
牛顿法的示意图在官方题解中给出了示意,这里只是简单地将其示意图截取下来:
简单来说,通过不断计算曲线上某点
(
x
0
,
x
0
2
−
c
)
(x_0, {x_0}^2-c)
(x0,x02−c)的切线与x轴的交点,我们就可以使此点慢慢趋近于真实的平方根
x
⋆
x^{\star}
x⋆,并且通过控制当前解与上次解之间的距离(在x轴上的距离差),我们可以控制解的相对精度。总而言之,在本题的迭代过程中,上次解和此次解的关系是:
x
i
+
1
=
1
2
×
(
x
i
+
c
x
i
)
x_{i+1} = \frac{1}{2} \times (x_i + \frac{c}{x_i})
xi+1=21×(xi+xic)。据此,我们可以写出代码,其中C就是我们要求平方根的数字,这里的代码将误差控制在
1
0
−
7
量
级
10^{-7}量级
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);
}
};
这篇博客记录了一种求解平方根问题的特殊解法——牛顿梯度下降法,据此可以控制解得相对精度,并且时间效率较高。