x的平方根
题目
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1
输入: 4 输出: 2
示例 2
输入: 8 输出: 2 说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
牛顿法
在数学中,一个数 的平方根指的是满足 的数,即平方结果等于的数。例如,4和-4都是16的平方根,因为 。
任意非负实数都有唯一的非负平方根,称为主平方根或算术平方根(英语:principal square root),记为 ,其中的符号√称作根号。例如,9的主平方根为3,记作,因为 并且3非负。被求平方根的数称作被开方数(英语:radicand),是根号下的数字或者表达式,即例子中的数字9。
正数有两个互为相反数的平方根:正数 与负数,可以将两者一起记为 。
负数的平方根在复数系中有定义。而实际上,对任何定义了开平方运算的数学对象都可考虑其「平方根」(例如矩阵的平方根)。
正数的平方根
若正整数x是平方数,则其平方根是整数。若正整数x不是平方数,则其平方根是无理数。
计算方法
长除式算法
长除式算平方根的方式也称为直式开方法,原理是 。
- 首先将要开平方根的数从小数点分别向右及向左每两个位一组分开,如98765.432内小数点前的65是一组,87是一组,9是一组,小数点后的43是一组,之后是单独一个2,要补一个0而得20是一组。如1 04.85 73得四组,顺序为1' 04. 85' 73'。
- 将最左的一组的数减去最接近又少于它的平方数,并将该平方数的开方(应该是个位数)记下。
- 将上一步所得之差乘100,和下一组数加起来。
- 将记下的数乘20,然后将它加上某个个位数,再乘以该个个位数,令这个积不大于但最接近上一步所得之差,并将该个个位数记下,且将上一步所得之差减去所得之积。
- 记下的数一次隔两位记下。
- 重覆第3步,直到找到答案。
- 可以在数字的最右补上多组的00'以求得理想的精确度为止。
牛顿法
如果要求的平方根,选取
例子:求 至6位有效数字。
代码实现
当轮入整数是0或1时,可以直得出其平方根。
牛顿法是在连续函数上逐步逼近,所以将中间变量定义为较大取值范围的double。
已知除了平方数,其它正整数的平方根都是无理数。所以,牛顿法只能通过不断迭代不断逼近平方根。实际实现中必须要有迭代中止条件,此处我们当前后两次迭代结果相差小于1e-12
即中止迭代。
复杂度分析
时间复杂度
理论上讲,牛顿法时间复杂度是。但其实际表现取决于初始值的选择和迭代中止条件(Tolerance)的选择。
请参考:
空间复杂度
使用了两个变量xn, xn1
,空间复杂度为。
二分搜索法
根据平方根定义,大于1的正整数平方根x是一个大于1小于S的实数。而本题只求平方根的整数部份,实际上就是求1至平方根x之间最大的整数。1至平方根x之间的整数是有限及有序的,二分搜索法可有效地在有限有序序列中搜索目标值。
步骤:
- 将1至S的整数序列切分为二
- 若中间值的平方小于或等于S,则继续在右半段序列中搜索:若中间值的平方大于S,则继续在左半段序列中搜索
- 当序列片断仅为一个整数时,其就是所求目标值
举个例子,求20的平方根的整数部份。20的平方根肯定是1至20之间,20平方根的整数部份一定是1至20之间19个整数中的一个。
- 将序列
1,2,...,18,19
二分为1,2,...,9
和10,...,19
,中间值10
的平方100
大于20
,继续在左半段搜索 - 将左半段序列
1,2,...,18,19
二分为1,2,3,4
和5,6,7,8,9
,中间值5
的平方25
大于20
,继续在左半段搜索 3.将左半段序列1,2,3,4
二分为1,2
和3,4
,中间值3
的平方9
小于20
,继续在右半段中搜索 - 将右半段序列
3,4
二分为3
和4
,中间值4
的平方16
小于20
,继续在右半段中搜索 - 右半段
4
仅有一个整数,所以4
就是所求值
代码实现
先处理一些简单的情况,如输入整数是0或1。
整数序列的起止初始为1和轮入整数,区间使用左闭右开模式。
二分搜索法是一种递归方法,这𥚃使用while
循环实现递归。递归中止条件为整数序列仅包含一个整数。
将整数序列不断地二分,通过中间值平方和输入值之间的大小关系,判断目标值是在左半段序列或是在右半段序列。
复杂度分析
时间复杂度
假设初始整数序列,即轮入整数值,为,二分法一共要进行次二分和判断中间值平方和轮入值关系。所以,时间复杂度为。
空间复杂度
使用了三个变量start, end, mid
,空间复杂度为。