题目链接

题目描述

实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

示例

示例1:

输入: 8 输出: 2 说明: 8 的平方根是 2.82842…, 由于返回类型是整数,小数部分将被舍去。

思路

思路1:二分查找

每一步都考虑 mid 的平方与 x 的关系,想象一个由 mid * mid 组成的有序数组 nums,此题其实就可以转换成查找右边界问题。
优化:
考虑将搜索范围由 [0, x] 缩小至 [0, x/2] ,为保证正确性,有 0069-x的平方根 - 图1 成立,即 0069-x的平方根 - 图2 ,因此我们要对 0069-x的平方根 - 图3 进行特判,但其实对于0069-x的平方根 - 图4 来说,算法的结果也是正确的。
经过优化,虽然复杂度没有变,但却可以有效降低运行时间。

思路2:牛顿法

牛顿法可以求解方程的近似解,在本题中,我们有 0069-x的平方根 - 图5,方程的零点为 0069-x的平方根 - 图6,因为我们只需要整数,所以可以从 0069-x的平方根 - 图7 开始迭代。
由迭代公式:0069-x的平方根 - 图8
得:0069-x的平方根 - 图9

思路3:换底法

我们可以进行如下换底操作: 0069-x的平方根 - 图10
注:exp()log() 返回值都为浮点数,因此最终计算结果可能会有精度损失,我们需要比较 ansans + 1 哪个是正确答案。

题解

思路1:二分查找

  1. class Solution {
  2. public:
  3. int mySqrt(int x) {
  4. if(1 == x){
  5. return 1;
  6. }
  7. int left = 0, right = x / 2;
  8. while(left <= right){
  9. int mid = ((right - left) >> 1) + left;
  10. if((long long)mid * mid <= x){
  11. left = mid + 1;
  12. }else{
  13. right = mid - 1;
  14. }
  15. }
  16. return left - 1;
  17. }
  18. };

思路2:牛顿法

class Solution {
   public:
    int mySqrt(int x) {
        if (x == 0) {
            return 0;
        }

        long i = x;
        while (i * i > x) {
            i = (i + x / i) / 2;
        }

        return (int)i;
    }
};

思路3:换底法

class Solution {
   public:
    int mySqrt(int x) {
        if (x == 0) {
            return 0;
        }
        int ans = exp(0.5 * log(x));
        return ((long long)(ans + 1) * (ans + 1) <= x ? ans + 1 : ans);
    }
};

复杂度分析

思路1:二分查找

  • 时间复杂度:0069-x的平方根 - 图11
  • 空间复杂度:0069-x的平方根 - 图12

    思路2:牛顿法

  • 时间复杂度:0069-x的平方根 - 图13

  • 空间复杂度:0069-x的平方根 - 图14

    思路3:换底法

  • 时间复杂度:0069-x的平方根 - 图15exp()log() 的时间复杂度我们认为是0069-x的平方根 - 图16

  • 空间复杂度:0069-x的平方根 - 图17