剑指 Offer 16. 数值的整数次方(快速幂)

232 阅读1分钟

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

每日刷题第37天 2021.02.02

数值的整数次方

题目

  • 实现 pow(xn) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。

示例

  • 示例1
输入: x = 2.00000, n = 10
输出: 1024.00000
  • 示例2
输入: x = 2.10000, n = 3
输出: 9.26100
  • 示例3
输入: x = 2.00000, n = -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25

提示

  • -100.0 < x < 100.0
  • -2^31 <= n <= 2^31-1
  • -10^4 <= x^n <= 10^4

拓展

  • 算数移位:最高位为符号位,存储有符号整型。
    • 正数:最高位为0,计算机中存储正数用原码
    • 负数:最高位为1,计算机中存储负数用补码(原码取反+1)
  • 逻辑移位:没有符号位,存储无符号整型。
  • 本题指数为负数时,有两种解决办法
    1. 将指数取绝对值变为正数,即:n = -n,x不变,最后将返回:1/ans
    2. 转换底数x1/xn不变,最后返回ans
  • 使用JS中的>>运算符的时候存在一个坑点
    • >>算数移位,因为题目中给的数据,负数可以取到-2^31,但是将其转换为正数后,就会超出有符号整型的最大值2^31-1,那么js内部就会将其转换为无符号整数进行存储,这时就不会超出。but此时再使用>>算数移位运算符就会出错。
    • >>>逻辑移位,解决方案,使用逻辑移位运算符即可。

解法

  • 递归方法:
    • n为奇数 -> (x^ 2/n)^2 * x
    • n为偶数 -> (x^ 2/n)^2
    • n = 0 -> 1 (递归的终止返回条件)
/**
 * @param {number} x
 * @param {number} n
 * @return {number}
 */
var myPow = function(x, n) {
  // 使用快速幂算法
  // 递归的思想
  // 1.奇数 a,n-1 * a
  // 2.偶数 a, n / 2
  // 3. a,0  1
  function fastPower (x,n) {
    if (n == 0) return 1;
    n = n < 0 ? -n : n;
    if (n % 2 == 0) {
      // 偶数
      let record = fastPower(x,n / 2);
      return record * record;
    }else {
      // 奇数
      return fastPower(x, n - 1) * x;
    }
  }
  if (n < 0) {
    // 指数是负数
    return (1 / fastPower(x,n)).toFixed(5);
  }else {
    return fastPower(x,n).toFixed(5);
  }
};
  • 非递归方法:使用while循环,计算机中存储的形式为二进制,因此可通过每次右移来判断是否需要累乘到ans中。
    • 为什么每一轮都要x *= x,原因如下(举例x = 3, n = 13),n二进制'1101',下面将其反过来写,便于观察
      1011
      33*3=99*3=2727*3=81
      不要
    • 由观察可知,不论为1还是为0,X都需要累乘。
/**
 * @param {number} x
 * @param {number} n
 * @return {number}
 */
var myPow = function(x, n) {
  // 非递归做法的快速幂
  if (x == 1 || n == 0) return 1;
  if (n == 1) return x;
  let ans = 1,flag = false;
  n > 0 ? flag = true : n = -n;
  while (n != 0) {
    if (n & 1 != 0) ans *= x;
    x *= x;
    // 可替换
    n >>>= 1;
    // 替换语句
    n = Math.floor(n / 2);
  }
  if (flag) return ans;
  else return 1 / ans; 
};

附录

  • 移位运算符>> >>>
  • 位运算符&:可以判断当前的值的奇偶性
  • 取固定小数位:toFixed(5)