LeetCode> 69. 求x的平方根

题目

地址:LeetCode 69. x的平方根

题目描述

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例1:

输入:x = 4
输出:2

示例2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

提示:

  • 0 <= x <= 231 - 1

解题思路

  • 方法一 暴力搜索

遍历[1, √x],找到最后一个i,满足i*i <= x,i即为所求。

    // 方法1:暴力搜索
    int mySqrt1(int x) {
        if (x <= 1) return x;

        long long i;
        for (i = 1; i * i <= x; ++i) {
        }

        if (i * i == x) return i;
        return i - 1;
    }
  • 方法二 二分法

求x平方根 <=> 求f(t) = t * t - x = 0的正根
由于f(t)是定义在[0, +∞)上的单调连续函数,因此可以找一个区间[a, b],然后不断缩小范围,来逼近f(t)=0位置。
要求f(a) * f(b) < 0,这样根t0必位于[a, b]。

可以取m = (a+b)/2,
当f(m) = 0,说明找到根了,m即为所求;
当f(m) < 0,说明a太小了,可以右移,让a=m+1;
当f(m) > 0,说明b太大了,可以左移,让b=m-1。

不断重复上面的取值,直到a > b,这样最后一个满足条件的m即为所求。

    // 方法2: 二分法 在[0, x]找k, 使得k = sqrt(x) <=> k * k = x,
    // ∵k是整数 ∴只保留整数t, 去掉小数部分
    // ∴t*t <= k*k = x
    // x平方根, 等价于求f(x) - x*x = 0的
    int mySqrt2(int x) {
        if (x <= 1) return x;
        int left = 0, right = x, mid;
        int res = x;

        while (left <= right) {
            long mid = left + (right - left) / 2;
            if (mid * mid <= x) {
                res = mid;
                left = mid + 1;
            }
            else {
                right = mid - 1;
            }
        }
        return res;
    }
  • 方法三 牛顿迭代法

对于f(x)=0求根问题,
求解方法:
x2 = x1 - f(x1)/f'(x1)

不断迭代求解x1,x2,终止条件:|x2 - x1| < eps,eps是定义的精度,通常是一个比较小的浮点数

    // 方法3:牛顿迭代法
    // x2 = x1 - f(x1)/f'(x1), f(x) = x*x - n
    // 求n平方根, 转为求f(x) = 0的正根. 这里的n就是题目中输入x
    // 而f'(x) = 2x
    // => x2 = x1 - (x1*x1-n)/(2x1)
    //       = 1/2 (x1 + n/x1)
    // 含义: 通过对接近零点的领域点做切线, 不断逼近零点, 最终十分靠近零点
    // 初始点, 可以任意取, 只要在合法范围内即可[0, +∞), 这里取x0=x
    int mySqrt(int x) {
        if (x <= 1) return x;
       
        double x0 = x, n = x;
        double x1 = x0;
        static constexpr double eps = 1e-7;
        while (true) {
            double x2 = 0.5 * (x1 + n / x1);
            if (fabs(x2 - x1) < eps) {
                break;
            }
            x1 = x2;
        }
        return static_cast<int>(x1);
    }

参考

用“牛顿迭代法”求根号2的近似值
牛顿迭代法求解平方根

posted @ 2023-06-09 10:49  明明1109  阅读(74)  评论(0编辑  收藏  举报