【算法-LeetCode】69. Sqrt(x)(二分查找)

69. Sqrt(x) - 力扣(LeetCode)

文章更新:2021年10月16日15:59:14

问题描述及示例

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例 1:
输入:x = 4
输出:2

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

提示:
0 <= x <= 231 - 1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sqrtx
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的题解

成功前的尝试

第一想法就是从 1 开始找到 x 的所有因数,然后根据找到的最后一对因数来决定返回结果。

/**
 * @param {number} x
 * @return {number}
 */
var mySqrt = function(x) {
  // fac用于存储一对对的因数
  let fac = [];
  // 从1开始找x的因数
  let n = 1;
  // 注意成对的因数都是各自往中间逼近的
  while(n <= x / n) {
    // 如果当前数字是x的因数
    if(!(x % n)) {
      // 则将当前数字以及与其配套的另一个因数放入fac中
      fac.push(n, x / n);
    }
    // 如果当前数字不是x的因数,则遍历下一个
    n++;
  }
  // 如果x是0,则返回0,如果不是的话就返回最后一对因数的平均值
  return x ? Math.floor((fac[fac.length-2] + fac[fac.length-1]) / 2) : 0;
};


提交记录
执行结果:解答错误
通过测试用例:12 / 1017
输入:5
输出:1
预期结果:2
时间:2021/10/16 14:03	

这个解法的错误就在于没有考虑到 x 的平方根可能离最后找到的那对因数都有一定的距离,不一定就是两者的平均值。比如 x = 37 时,其平方根结果是 6,但是其最后一对因数是 137,两者去除小数部分的平均值为 19

我的题解1(暴力解法)

这种方法和上面的尝试有相似之处。也是遍历的思路。关键的命中条件判断逻辑就是如果 x 在 n2 和 (n+1)2 之间,那么 x 的平方根结果去除小数部分就是 n

/**
 * @param {number} x
 * @return {number}
 */
var mySqrt = function(x) {
  // 如果x是0,则直接返回0
  if(!x) {
    return 0;
  }
  // 从1开始遍历,
  let n = 1;
  // 如果当前数字的值小于等于另一个因数(虽然该因数可能不是整数)
  while(n <= x / n) {
    // 如果当前数字的平方小于等于x,且下一个数字的平方大于x,
    // 说明当前数字就是我们要找的平方数,直接将其返回
    if(n * n <= x && x < (n + 1) * (n + 1)) {
      return n;
    }
    // 否则的话就遍历下一个数字
    n++;
  }
};


提交记录
1017 / 1017 个通过测试用例
状态:通过
执行用时:180 ms, 在所有 JavaScript 提交中击败了5.29%的用户
内存消耗:39.2 MB, 在所有 JavaScript 提交中击败了69.55%的用户
时间:2021/10/16 14:46

可以看到上面这种解法的性能还是比较低的。因为这相当于是要遍历一些不必要的元素。所以下面的二分法就显得更高效一点。

我的题解2(二分查找)

更新:2021年10月16日15:57:37

小憩一会儿,回来继续~

其实本题也可以用二分查找的思路来寻找目标值,因为查找过程中所涉及到的数字都是有序的。有关二分查找的思路,可以看下方博客:

参考:【算法-LeetCode】704. 二分查找_赖念安的博客-CSDN博客

本题的思路和上面的二分查找是一样的,也是利用元素大小有序的特点进行对半地筛选工作。而本题就相当于是在 1 ~ x 这些数中寻找符合条件的值。

/**
 * @param {number} x
 * @return {number}
 */
var mySqrt = function (x) {
  // 如果x是0或1,直接返回x本身即可
  if (x === 0 || x === 1) {
    return x;
  }
  // 初始化左右指针分别指向待查区间的头部和尾部,这里left初始化为0也可以
  let left = 1;
  let right = x;
  // mid指针用于指示区间的中点,初始值是什么都无所谓,因为后面会被覆盖
  let mid = 0;
  // 开始搜寻,直到区间长度小于0
  while (left <= right) {
    // 计算当前区间的中点位置,为了防止溢出,这里的计算不是直接采用(left+right)/2
    mid = Math.floor(left + (right - left) / 2);
    // 如果当前中点的值的平方比x大,则让right指针移到mid前一位,
    // 这里也是为了防止溢出,所以不是直接采用 mid * mid
    if (mid > x / mid) {
      right = mid - 1;
    } else if (mid < x / mid) {
      // 如果当前中点的值的平方比x小,则让left指针移到mid后一位,
      left = mid + 1;
    } else {
      // 如果当前中点的值的平方恰好是x则直接返回结果
      return mid;
    }
  }
  // 如果上面没有搜寻到合适的值,则此时left和right指针一定停留在目标值的附近,
  // 而且此时的left指针一定是在right指针的后一位,而因为题目要求去除结果的小数部分
  // 所以我们就可以去较小的right值作为结果
  return right;
};


提交记录
1017 / 1017 个通过测试用例
状态:通过
执行用时:80 ms, 在所有 JavaScript 提交中击败了83.33%的用户
内存消耗:39.4 MB, 在所有 JavaScript 提交中击败了31.60%的用户
时间:2021/10/16 15:54

官方题解

更新:2021年7月29日18:43:21

因为我考虑到著作权归属问题,所以【官方题解】部分我不再粘贴具体的代码了,可到下方的链接中查看。

更新:2021年10月16日14:48:51

参考:x 的平方根 - Sqrt(x) - 力扣(LeetCode)

【更新结束】

有关参考

更新:2021年10月16日15:57:22
参考:【算法-LeetCode】704. 二分查找_赖念安的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值