50. Pow(x, n)
实现 pow(x, n) ,即计算 x 的 n 次幂函数。
示例 1:
输入: 2.00000, 10 输出: 1024.00000
示例 2:
输入: 2.10000, 3 输出: 9.26100
示例 3:
输入: 2.00000, -2 输出: 0.25000 解释: 2-2 = 1/22 = 1/4 = 0.25
说明:
- -100.0 < x < 100.0
- n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。
解法一:
//时间复杂度O(n), 空间复杂度O(1)
class Solution {
public:
double myPow(double x, int n) {
if(x == 1.0) return 1.0;
if(x == 0.0 && n != 0) return 0.0;
if(n == 0) return 1.0;
long n2 = n;
if(n2 < 0) {
x = 1 / x;
n2 = -n2;
}
double res = x;
long cnt = 1;
while(cnt < n2) {
if(cnt <= n2 / 2) {//节省时间
res *= res;
cnt *= 2;
}
else {
res *= x;
cnt++;
}
}
return res;
}
};
解法二:
//时间复杂度O(logn), 空间复杂度O(1)
class Solution {
public:
double myPow(double x, int n) {
long n2 = n;
if(n2 < 0) {
x = 1 / x;
n2 = -n2;
}
double res = 1;
double curPdt = x;
while(n2 > 0) {
if(n2 % 2 == 1) res *= curPdt;
curPdt *= curPdt;
n2 /= 2;
}
return res;
}
};
解法一:
是暴力法的改版,使用res作为中间累乘的结果,循环里的每一步都将res自乘以x的某次幂。如果当前累乘次数cnt的2倍不大于n时,说明可以将res直接变为其平方,cnt计数直接变为2倍;否则就只乘x的1次幂,cnt++。最恶劣的情况,需要进行n/2次也就是线性时间。
解法二:
是解法一的改版,使用了额外的一个变量curPdt代表当前幂,curPdt初始为x,自平方增长。此解法将n以二进制位的形式来看,如果其最低位为1,说明res要自乘以curPdt;否则只需要增长curPdt即可。
总体的效果就是,要找出一个x的幂的序列,该序列的和刚好为n,且序列的元素个数最小。
//核心代码
while(n2 > 0) {
if(n2 % 2 == 1) res *= curPdt;//如果位为1,需要乘入res
curPdt *= curPdt;//curPdt继续自平方增长
n2 /= 2;//n2右移位
}
例如输入为(2,18),18的二进制表示为 0001 0010b
,看位为1的位就容易知道,18可拆分为 2 加 16:0001 0000b + 0000 0010b
,也就是pow(2, 18) = 2^18 = 2^2 * 2^16 = 4294967296。
以下是代码的运行步骤:
循环次数 res curPdt curPdt中x的幂次 n2
0 1 x=2 1 18(0)
1 1 4 2 9(1)
2 4 16 4 4(0)
3 4 256 8 2(0)
4 4 65536 16 1(1)
5 262144 4294967296 32 0(终止)
以上乘入res的x的幂次为:2,16。
2019/10/09 13:37