二分法03:x 的平方根
Posted 炫云云
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分法03:x 的平方根相关的知识,希望对你有一定的参考价值。
x 的平方根
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842...,
由于返回类型是整数,小数部分将被舍去。
方法一:二分查找
由于 x x x 平方根的整数部分 ans \\textit{ans} ans 是满足 k 2 ≤ x k^2 \\leq x k2≤x的最大 k k k 值,因此我们可以对 k k k 进行二分查找,从而得到答案。
二分查找的下界为 0,上界可以粗略地设定为 x x x。在二分查找的每一步中,我们只需要比较中间元素 mid \\textit{mid} mid 的平方与 x x x 的大小关系,并通过比较的结果调整上下界的范围。
在判断是否满足条件要用除,不能直接mid * mid,因为如果mid过大会溢出,除的话分2种,一种是x / mid < mid,说明 mid大了, 即最优解在[left,mid]
,压缩右边界,即right =mid
第2种情况是 x / mid >= mid,说明 mid 太小了,即最优解在[mid+1,right]
,那么就让下边界往上去一点, left = mid +1
,为什么这里不减1呢?因为控制left总比x的根大一点,这样返回最终结果直接返回 left - 1即可,代码如下:
class Solution(object):
def mySqrt(self, x):
"""
:type x: int
:rtype: int
"""
if x==0 or x==1:
return x
left=0
right = x
while left<right:
mid = left + (right - left) // 2 # 防止计算时溢出
if mid> x/mid: # 最优解在`[left,mid]`
right =mid
else: # 最优解在`[mid+1,right]`
left = mid +1
return left-1
复杂度分析
时间复杂度: O ( log x ) O(\\log x) O(logx) ,即为二分查找需要的次数。
空间复杂度: O ( 1 ) O(1) O(1)。
方法二:牛顿迭代
牛顿法求根,原理是使用函数 f ( x ) f(x) f(x) 的泰勒级数的前面几项来寻找方程 f ( x ) = 0 f(x)=0 f(x)=0 的根。
将函数 f ( x ) f(x) f(x) 在 x 0 x_0 x0 处展开成泰勒级数:
f ( x ) = f ( x 0 ) + f ′ ( x 0 ) ( x − x 0 ) + 1 2 f ′ ′ ( x 0 ) ( x − x 0 ) 2 + … (5) f(x)=f(x_0)+f^{'}(x_0)(x-x_0)+\\frac{1}{2}f^{''}(x_0)(x-x_0)^2+\\dots \\tag5 f(x)=f(x0)+f′(x0)(x−x0)+21f′′(x0)(x−x0)2+…(5)
取其线性部分,作为 f ( x ) f(x) f(x) 的近似,则可用 f ( x 0 ) + f ′ ( x 0 ) ( x − x 0 ) = 0 f(x_0)+f^{'}(x_0)(x-x_0)=0 f(x0)+f′(x0)(x−x0)=0 的解来近似 f ( x ) = 0 f(x)=0 f(x)=0 的解,其解为
x 1 = x 0 − f ( x 0 ) f ′ ( x 0 ) (6) x_1=x_0-\\frac{f(x_0)}{f^{'}(x_0)}\\tag6 x1=x0−f′(x0)f(x0)(6)
由于对 f ( x ) f(x) f(x) 的近似只是一阶展开,因此 r r r 并非 f ( x ) = 0 f(x)=0 f(x)=0 的解,只能说 f ( x 1 ) f(x_1) f(x1) 比 f ( x 0 ) f(x_0) f(x0) 更接近0。于是,考虑迭代求解:
x n + 1 = x n − f ( x n ) f ′ ( x n ) (7) x_{n+1}=x_{n}-\\frac{f(x_n)}{f^{'}(x_n)} \\tag7 xn+1=xn−f′(xn)f(xn)(7)
由于牛顿法是基于当前位置的切线来确定下一次的位置,所以牛顿法又被很形象地称为是"切线法"。牛顿法的搜索路径(二维情况)如下图所示:
牛顿法搜索动态示例图:
为了叙述方便,我们用 C 表示待求出平方根的那个整数。显然,C 的平方根就是函数
y
=
f
(
x
)
=
x
2
−
C
y = f(x) = x^2 - C
y=f(x)=x2−C
的零点。我们选择
x
0
=
C
x_0 = C
x0=C 作为初始值。
f
′
(
x
)
=
2
x
f^{'}(x) = 2 x
f′(x)=2x
由7算式,新的迭代结果
x
n
+
1
=
x
n
−
x
n
2
−
C
2
x
n
=
1
2
(
x
n
+
C
x
n
)
x_{n+1}=x_{n}- \\frac{x_n^2 - C}{2x_n} = \\frac{1}{2}\\left(x_n + \\frac{C}{x_n}\\right)
xn+1=xn−2xnxn2−C=21(xn+xnC)
在进行 k k k 次迭代后, x k x_k xk 的值与真实的零点 s q r t C sqrt{C} sqrtC 足够接近,即
以上是关于二分法03:x 的平方根的主要内容,如果未能解决你的问题,请参考以下文章