快速幂算法(Binary Exponentiation)是计算幂运算的高效方法,它基于一个简单但强大的数学原理:任何整数都可以表示为二进制形式,而幂运算可以通过这种二进制表示进行分解优化。
传统计算xⁿ的方法是通过n-1次乘法:
c复制double result = 1;
for(int i=0; i<n; i++){
result *= x;
}
这种方法的时间复杂度是O(n),当n很大时(比如n=2³¹)效率极低。
快速幂的核心突破在于发现:
code复制xⁿ = x^(bₖ·2ᵏ + ... + b₁·2¹ + b₀·2⁰) = x^(bₖ·2ᵏ) × ... × x^(b₀·2⁰)
其中bᵢ是n的二进制表示中的各位(0或1)。
以x¹⁰为例:
code复制10的二进制 = 1010
x¹⁰ = x^(8+2) = x⁸ × x²
计算过程可以转化为:
这样只需要4次乘法(而不是10次),时间复杂度降为O(log n)。
当n为负数时,xⁿ = 1/x⁻ⁿ。但直接取反可能遇到边界情况:
c复制if(n < 0) {
x = 1/x;
n = -n; // 这里可能溢出!
}
当n=-2³¹(即INT_MIN)时,直接取反会导致溢出,因为2³¹超出了int的正数范围。解决方案是使用更大范围的long long类型:
c复制long long N = n;
if(N < 0) {
x = 1/x;
N = -N; // 安全转换
}
以x=2, n=10为例:
| 迭代次数 | N (二进制) | 当前位 | result | x |
|---|---|---|---|---|
| 初始 | 1010 | - | 1 | 2 |
| 1 | 101 | 0 | 1 | 4 (2²) |
| 2 | 10 | 1 | 1×4=4 | 16 (4²) |
| 3 | 1 | 0 | 4 | 256 (16²) |
| 4 | 0 | 1 | 4×256=1024 | - |
c复制double myPow(double x, int n) {
long long N = n;
if(N < 0) {
x = 1/x;
N = -N;
}
double result = 1.0;
while(N > 0) {
if(N & 1)
result *= x;
x *= x;
N >>= 1;
}
return result;
}
递归基于公式:
code复制xⁿ = (x^(n/2))² 当n为偶数
xⁿ = (x^(n/2))² × x 当n为奇数
计算x¹⁰的递归过程:
code复制fastPow(2,10)
fastPow(2,5)
fastPow(2,2)
fastPow(2,1)
fastPow(2,0) return 1
return 1² × 2 = 2
return 2² = 4
return 4² × 2 = 32
return 32² = 1024
c复制double fastPow(double x, long long n) {
if(n == 0) return 1;
double half = fastPow(x, n/2);
return n%2 == 0 ? half*half : half*half*x;
}
double myPow(double x, int n) {
long long N = n;
return N >= 0 ? fastPow(x, N) : 1/fastPow(x, -N);
}
两种方法都是O(log n),因为每次都将问题规模减半。
| 方法 | 空间复杂度 | 说明 |
|---|---|---|
| 迭代法 | O(1) | 只使用固定数量的变量 |
| 递归法 | O(log n) | 递归调用栈深度为log n |
c复制bool isPowerOfTwo(int n) {
return n > 0 && (n & (n-1)) == 0;
}
c复制int hammingWeight(uint32_t n) {
int count = 0;
while(n) {
n &= n-1;
count++;
}
return count;
}
快速幂在RSA等加密算法中有重要应用,计算(a^b) mod m:
c复制long long modPow(long long a, long long b, long long m) {
long long res = 1;
a %= m;
while(b > 0) {
if(b & 1) res = (res*a) % m;
a = (a*a) % m;
b >>= 1;
}
return res;
}
使用位运算代替除法/取模:
循环展开:对于已知范围的n可以手动展开部分循环
使用查表法:对频繁计算的小指数预先缓存结果
应包括以下边界情况:
c复制x=2.0, n=0 → 1
x=1.0, n=INT_MAX → 1
x=2.0, n=INT_MIN → 0
x=0.0, n=10 → 0
x=0.0, n=-1 → INF(需特殊处理)