二分法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 k2x的最大 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)(xx0)+21f(x0)(xx0)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)(xx0)=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=x0f(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=xnf(xn)f(xn)(7)

由于牛顿法是基于当前位置的切线来确定下一次的位置,所以牛顿法又被很形象地称为是"切线法"。牛顿法的搜索路径(二维情况)如下图所示:

牛顿法搜索动态示例图:

img

为了叙述方便,我们用 C 表示待求出平方根的那个整数。显然,C 的平方根就是函数
y = f ( x ) = x 2 − C y = f(x) = x^2 - C y=f(x)=x2C

的零点。我们选择 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=xn2xnxn2C=21(xn+xnC)

在进行 k k k 次迭代后, x k x_k xk 的值与真实的零点 s q r t C sqrt{C} sqrtC 足够接近,即

以上是关于二分法03:x 的平方根的主要内容,如果未能解决你的问题,请参考以下文章

计蒜课_二分法求平方根

Leetcode69. x 的平方根(二分)

leetcode Sqrt(x)二分法查找平方根

求平方根的算法 牛顿迭代法和二分法

leetcode69 X的平方根的几种解法

LeetCode 69 x的平方根[二分法] HERODING的LeetCode之路