[路飞]_程序员必刷力扣题: 69. x 的平方根

131 阅读1分钟

「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战

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

二分查找

思路

有题意可知,我们求解的都是非负整数,如果开根是小数,那么省略小数部分,例如:10开根是3.多 直接返回3即可

如果我们不用内置方法的话,自己去求解,那么就只能一个一个的数字去试一下了,那么怎么提高我们试的效率呢?

因为开根的整数一定是0-x之间的数字,且0-x之间是有序的,这里我们很容易能够联想到二分查找的办法

所以我们这里用left表示左端起点,right表示终点,mid为left和right的中点向下取整

  • 如果mid的平方大于x,那么mid不符合题意可以直接省略了,所以让right = mid - 1
  • 如果mid的平方小于x,那么分两种情况
    • mid+1的平方大于x,则不能在让left=mid+1,直接将当前mid赋值给最后结果ans
    • mid+1的平方小于x,则mid不符合题意,省略,让left = mid + 1
  • 如果mid的平方等于x,那么直接将mid赋值给最后结果ans

这样每次都是从0 ~ x中开始选取,但是很明显,当x = 4的时候,结果刚好为2,是4的一半;当x > 4的时候,其开根结果都是小于x>>1(x的一半)的,这样就能将筛选范围缩小一半,所以这里我单独处理了小于4的情况

var mySqrt = function (x) {
    // 二分查找
    if (x === 0) return 0;
    if (x < 4) return 1;

    var left = 2,
      right = x >> 1;
    var ans = 0;
    var mid = (left + right) >> 1;
    while (left < right) {
      // 大于的情况
      if (mid * mid > x) right = mid - 1;
      // 小于的情况
      if (mid * mid < x) {
        if ((mid + 1) * (mid + 1) > x) {
          ans = mid;
          break;
        } else {
          left = mid + 1;
        }
      }
      // 等于的情况
      if (mid * mid === x) {
        ans = mid;
        break;
      }
      mid = (left + right) >> 1;
    }
    return ans;
  };