❓剑指 Offer 16. 数值的整数次方
难度:中等
实现 pow(x, n) ,即计算 x
的 n
次幂函数(即,
x
n
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 / 2 2 = 1 / 4 = 0.25 2^{-2} = 1/2^2 = 1/4 = 0.25 2−2=1/22=1/4=0.25
提示:
- − 100.0 < x < 100.0 -100.0 < x < 100.0 −100.0<x<100.0
- − 2 31 < = n < = 2 31 − 1 -2^{31} <= n <= 2^{31}-1 −231<=n<=231−1
n
是一个整数- 要么
x
不为零,要么n > 0
。 - − 1 0 4 < = x n < = 1 0 4 -10^4 <= x^n <= 10^4 −104<=xn<=104
注意:本题与 50. Pow(x, n) 相同。
💡思路:分治
最直观的解法是将 x
重复乘 n
次,x*x*x...*x
,那么时间复杂度为
O
(
N
)
O(N)
O(N)。
因为乘法是可交换的,所以可以将上述操作拆开成两半 (x*x..*x)
* (x*x..*x)
,两半的计算是一样的,因此只需要计算一次。而且对于新拆开的计算,又可以继续拆开。
这就是 分治思想,将原问题的规模拆成多个规模较小的子问题,最后子问题的解合并起来。
本题中子问题是 x n / 2 x^{n/2} xn/2,在将子问题合并时将子问题的解乘于自身相乘即可。
- 但如果
n
不为偶数,那么拆成两半还会剩下一个x
,在将子问题合并时还需要需要多乘于一个x
。
x n = { x n / 2 ∗ x n / 2 n % 2 = 0 x ∗ ( x n / 2 ∗ x n / 2 ) n % 2 = 1 x^n=\left\{\begin{array}{rl}x^{n/2}*x^{n/2}&\quad n\%2=0\\x*(x^{n/2}*x^{n/2})&\quad n\%2=1\end{array}\right. xn={xn/2∗xn/2x∗(xn/2∗xn/2)n%2=0n%2=1
因为
(
x
∗
x
)
n
/
2
(x*x)^{n/2}
(x∗x)n/2 可以通过递归求解,并且每次递归 n
都减小一半,因此整个算法的时间复杂度为
O
(
l
o
g
N
)
O(logN)
O(logN)。
🍁代码:(C++、Java)
方法一:快速幂 + 递归
C++
class Solution {
private:
double pow(double x, long n){
if(n == 0) return 1;
if(n == 1) return x;
if(n % 2 == 0) return pow(x * x, n / 2);
return x * pow(x * x, n / 2);
}
public:
double myPow(double x, int n) {
long long N = n < 0 ? -(long long)n : n;
double ans = pow(x, N);
return n < 0 ? 1 / ans : ans;
}
};
Java
class Solution {
private double pow(double x, long n){
if(n == 0) return 1;
if(n == 1) return x;
if(n % 2 == 0) return pow(x * x, n / 2);
return x * pow(x * x, n / 2);
}
public double myPow(double x, int n) {
long N = n < 0 ? -(long)n : n;
double ans = pow(x, N);
return n < 0 ? 1 / ans : ans;
}
}
方法二:快速幂 + 迭代
C++
class Solution {
public:
double myPow(double x, int n) {
if(n == 0) return 1;
if(n == 1) return x;
long long N = n < 0 ? -(long long)n : n;
double ans = 1;
while( N != 1){
if(N % 2 != 0) ans *= x;
x *= x;
N /= 2;
}
ans *= x;
return n < 0 ? 1.0 / ans : ans;
}
};
Java
class Solution {
public double myPow(double x, int n) {
if(n == 0) return 1;
if(n == 1) return x;
long N = n < 0 ? -(long)n : n;
double ans = 1;
while( N != 1){
if(N % 2 != 0) ans *= x;
x *= x;
N /= 2;
}
ans *= x;
return n < 0 ? 1.0 / ans : ans;
}
}
🚀 运行结果:
🕔 复杂度分析:
- 时间复杂度:
O
(
l
o
g
n
)
O(logn)
O(logn),即为对
n
进行二进制拆分的时间复杂度。 - 空间复杂度: O ( 1 ) O(1) O(1);法一递归的函数调用会使用栈空间所以复杂度为 O ( l o g n ) O(logn) O(logn)。
题目来源:力扣。
放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我LeetCode主页 / CSDN—力扣专栏,每日更新!