面试刷题之 Pow(x, n)

448 阅读1分钟

又到了金三银四,遥想当年,这个时候不是在面试,就是在准备面试。今年虽然没有去面试,不过还是照例在 leetcode 上刷了几道题。

Pow(x, n)

题目地址 leetcode-cn.com/problems/po…

实现 pow(x, n) ,即计算 xn 次幂函数(即,x^n)。

示例 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

常规解法

咋一看这道题 so easy,一个 for 循环就搞定了,代码如下:

/**
 * JavaScript 版本
 * 计算 x 的 n 次幂函数(即,x^n)
 * @param {number} x
 * @param {number} n
 * @return {number}
 */
var myPow = function (x, n) {
  let res = 1
  for (let i = 0; i < n; i++) {
    res *= x
  }
  return res
}

如果你真的在面试中就这样交卷了,大概率是得不到高分的,原因有二:

  • 算法实现的不完整,没有考虑 n < 0 的情况
  • 没有弄清楚面试官真正要考的点,他真的是想考你 for 循环吗?

面试官:“这个算法的时间复杂度是多少?”
面试者:“n
面试官:“有没有更优的解?”
面试者:“嗯..."

其实弄这么一道看似很简单的算法题来进行面试,无非考察一下几点:

  • 代码风格。主要是看变量命名、代码缩进、空格等是否规范。
  • 算法完整性。主要是看代码是否覆盖主要的测试用例。
  • 解决问题的能力。常规解法可能人人都会,你是否考虑过更优的解,是否能提出更优的解,这主要取决于一个人平时的积累和遇到问题的解决能力。

更优解法

在给出更优解法前,先来说几个数学知识。

  1. n < 0 时, x^n = 1/(x^abs(n)), 例如: 5^(-2) = 1 / (5^2)
  2. 任意一个正整数,都可以被 2 的不同幂求和得出,说的直白点,任意整数都可以表示成二进制。
  3. n = i + j 时, x^n = x^i * x^j

有了这三个知识点,我们就可以优化上个问题的解了

/**
 * JavaScript 版本
 * 计算 x 的 n 次幂函数(即,x^n)
 * @param {number} x
 * @param {number} n
 * @return {number}
 */
var myPow = function (x, n) {
  let res = 1
  let q = n < 0 ? -n : n
  while (q > 0) {
    const mod = q % 2
    if (mod) {
      res *= x
    }
    x *= x
    q = (q - mod) / 2
  }
  if (n < 0) {
    res = 1 / res
  }
  return res
}

我们再来看这个算法的时间复杂度:log(n)
现在我们已经成功优化了最初的求幂算法。

更进一步,我们还可以把除 2 取余替换成位运算,并考虑 x = 0 的情况,代码如下:

/**
 * JavaScript 版本
 * 计算 x 的 n 次幂函数(即,x^n)
 * @param {number} x
 * @param {number} n
 * @return {number}
 */
var myPow = function (x, n) {
  if (x === 0) return 0
  let res = 1
  let q = n < 0 ? -n : n
  while (q > 0) {
    if (q & 1) {
      res *= x
    }
    x *= x
    q = q >> 1
  }
  if (n < 0) {
    res = 1 / res
  }
  return res
}

至此,我们就可以交卷提交代码了。

思考

  • 上面的解法都没有过多考虑 x = 0, n = 0 的情况,0 的 0 次方本身就是一个悬而未决的数学问题。
  • 没有做参数验证,如果在写类库,参数验证是不可少的,当入参不合法时,要抛出相应的异常,感兴趣的可以自己加上试试。

如果有更优的解,欢迎留言评论。

总结

看似一道很简单的面试题,其实考察的点还是很多的,如果不注意,容易载跟头,这就要求我们平时多思考多积累多练习。

在这里祝所有跳槽的同学 offer 多多。(公众号:ANOV可视化)