LeetCode50 Pow(x, n) & 剑指Offer 16 数值的整数次方
题目
解题
几个注意点:
- n 可正、可负、可为 0。一个数的 0 次方等于 1,严格来讲,0 的 0 次方是没有意义的,如果要追求统一,可以设置为1;n 为负整数时,结果是 1 x − n {1 \over x^{-n}} x−n1
- x 可正、可负、可为 0。x 为 0 时,0 的 0 次方是 1,0 的正整数次方是 0,0 的负整数次方结果是 Inf,可以使用 1 0 − n 1 \over 0^{-n} 0−n1 得到
- − 2 31 < = n < = 2 31 − 1 , − 2 31 -2^{31} <= n <= 2^{31}-1,-2^{31} −231<=n<=231−1,−231 转换成正整数时,有些语言会产生越界,要使用 长整型的变量 来存储。因为 JS 是一个弱类型的语言,不会产生越界问题,故代码中没有做处理
- 如果使用位运算来完成除 2 的操作,因为 m 的最大取值会是
2
31
2^{31}
231(
−
2
31
<
=
n
<
=
2
31
−
1
-2^{31} <= n <= 2^{31}-1
−231<=n<=231−1),所以一定要用 无符号的移位(JS 中是
>>>
,不然第 32 位的 1 会让 m 变成负数)。
解题一:快速幂 + 递归
quickMul 中的基础条件是 if (m === 0) return 1;
可以解决 n = 0 的情况;x = 0 并且 n 不等于 0 (n = 0 的情况基础条件已经处理完毕)时,一定会递归计算
x
1
x^1
x1,结果是 0,所以 x = 0 也可以正常处理。
代码使用位运算来完成除 2 的操作,因为 m 的最大取值会是
2
31
2^{31}
231(
−
2
31
<
=
n
<
=
2
31
−
1
-2^{31} <= n <= 2^{31}-1
−231<=n<=231−1),所以一定要用>>>
(无符号的移位,不然第 32 位的 1 会让 m 变成负数)。
// javascript
var myPow = function(x, n) {
return n >= 0 ? quickMul(x, n) : 1 / quickMul(x, -n);
};
const quickMul = (x, m) => {
if (m === 0) return 1;
// 无符号的移位!!!
const y = quickMul(x, m >>> 1);
let res = y * y;
if ((m & 1) === 1) {
res *= x;
}
return res;
};
解题二:快速幂 + 迭代
7
=
0
b
111
,
a
7
=
a
4
∗
a
2
∗
a
1
7 = 0b111,a^7 = a^4 * a^2 * a^1
7=0b111,a7=a4∗a2∗a1。
n = 0 时进不了 while 循环,ans 为初始值 1,返回值是 1;x = 0 且 n 不为 0 的情况下 x_contribute 永远为 0,循环结束后 ans 为 0,符合预期。
// javascript
const myPow = (x, n) => {
let m = n >= 0 ? n : -n;
// 贡献的初始值为 x
let x_contribute = x;
let ans = 1;
// 在对 m 进行二进制拆分的同时计算答案
while (m > 0) {
if ((m & 1) == 1) {
// 如果 m 二进制表示的最低位为 1,那么需要计入贡献
ans *= x_contribute;
}
// 将贡献不断地平方
x_contribute *= x_contribute;
// 舍弃 m 二进制表示的最低位,这样我们每次只要判断最低位即可
m >>>= 1;
}
return n >= 0 ? ans : 1.0 / ans;
};