又到了金三银四,遥想当年,这个时候不是在面试,就是在准备面试。今年虽然没有去面试,不过还是照例在 leetcode 上刷了几道题。
Pow(x, n)
题目地址 leetcode-cn.com/problems/po…
实现 pow(x, n) ,即计算
x的n次幂函数(即,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”
面试官:“有没有更优的解?”
面试者:“嗯..."
其实弄这么一道看似很简单的算法题来进行面试,无非考察一下几点:
- 代码风格。主要是看变量命名、代码缩进、空格等是否规范。
- 算法完整性。主要是看代码是否覆盖主要的测试用例。
- 解决问题的能力。常规解法可能人人都会,你是否考虑过更优的解,是否能提出更优的解,这主要取决于一个人平时的积累和遇到问题的解决能力。
更优解法
在给出更优解法前,先来说几个数学知识。
- 当
n < 0时,x^n = 1/(x^abs(n)), 例如: 5^(-2) = 1 / (5^2) - 任意一个正整数,都可以被
2的不同幂求和得出,说的直白点,任意整数都可以表示成二进制。 - 当
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可视化)