LeetCode - 解题笔记 - 69 - Sqrt(x)

Solution 1

这道题乍一看应该是二分查找,不断尝试枚举整数的平方结果和输入的关系来确定平方根的整数位。但这样做有两个问题:需要留意乘法结果可能会超出int甚至是long;控制精度也不灵活。然后我上网上搜索了一下,发现了之前学习的牛顿搜索法可以解决这个问题。

这里用到的其实就是用牛顿法解方程,通过更快的下降方法实现虽然理论时间复杂度相同,但是实际速度比二分查找快的解决方案。记输入为 C C C,其对应平方根为 x x x,那么确定一个函数关系:

f ( x ) = x 2 − C f(x) = x^2 - C f(x)=x2C

平方根就是这个函数取值为0等时候。那么构造牛顿法迭代式:

x i + 1 = x i − f ( x i ) f ′ ( x i ) = x i 2 + C 2 x i x_{i + 1} = x_i - \frac{f(x_i)}{f^\prime(x_i)} = \frac{x_i}{2} + \frac{C}{2 x_i} xi+1=xif(xi)f(xi)=2xi+2xiC

整体来看,牛顿法的搜索步长是二次步进,因此时间复杂度是对数线性复杂度,但是由于方程本身是凸函数,搜索速度实际上比二分快很多,而且搜索质量可以通过误差上界控制。

  • 时间复杂度: O ( log ⁡ ( n ) ) O(\log(n)) O(log(n)),上面已经解释了,实际实现比二分快
  • 空间复杂度: O ( 1 ) O(1) O(1),因为只维护常数个状态量
class Solution {
public:
    int mySqrt(int x) {
        if (x == 0) {
            return 0; // 不然后面有一步计算迭代会出问题
        }

        // 牛顿下降
        double C = x, xPrev = x, eps = 1e-7;
        while (true) {
            double xNext = 0.5 * (xPrev + C / xPrev);
            if (fabs(xPrev - xNext) < eps) {
                break;
            }
            xPrev = xNext;
        }
        return int(xPrev);
    }
};

Solution 2

Solution 1的Python实现

class Solution:
    def mySqrt(self, x: int) -> int:
        if x == 0: return 0
        
        C = float(x)
        xPrev = float(x)
        eps = 1e-7
        while True:
            xNext = 0.5 * (xPrev + C / xPrev)
            if math.fabs(xPrev - xNext) < eps: break
            xPrev = xNext
            
        return int(xPrev)

你可能感兴趣的:(LeetCode解题笔记,leetcode,算法)