算法|快速幂
完成阅读您将会了解快速幂的:
- 算法思想
- 实现步骤
- 实践范例(C++/Rust)
1. 算法思想
普通幂运算可以表达为\(a^n=\prod_{i=1}^{n}a\)。这样求解理论上需要进行n-1次乘法运算,时间复杂度为\(\Theta(n)\),且每次的乘数总是原先的a,浪费了CPU运算性能。因此快速幂(Exponentiating by Squaring)算法根据指数运算法则通过反复平方拆分指数,将线性运算次数降至对数级,时间复杂度为\(\Theta(\lg n)\)。例如\(a^{27}\)可以拆成\(a^1\times a^2 \times a^8\times a^{16}\Leftrightarrow a^{2^0+2^2+2^3+2^4}\)。原本26次运算被减至7次(其中,4次用于平方运算,3次用于结果运算)。值得注意的是,快速幂是一种高效的算法,但不保证每次拆分都是最优方案。例如可以进一步将\(a^{27}\)拆分为运算次数只有6的\(((a^3)^3)^3\Leftrightarrow a^{3\times 3\times 3}\)。至于如何寻找最优指数拆分序列,当前尚没有简单高效的方案。
经过计算机科学家不断地研究,当前快速幂算法已经衍生许多个优秀版本。本文只介绍了最基础的一种。
2. 实现步骤
- 将结果y初始化为1;
- 如果指数n为奇,将当前底数x乘进结果;
- 将底数平方;
- 将指数除以2;
- 若指数仍然大于零则从第2步开始重复直至n不大于零。
实际编程中由于计算机操作系统位数限制,为防止结果溢出,会将每一步的结果取模。因为取模操作并不是该算法的关键内容,因此实践示例中并没有添加取模。另外,模运算是一个代价昂贵的运算。
3. 实践范例(C++/Rust)
问题描述:
给定整数x,求其n次幂y。
输入:x,n
输出:y
解答思路:
利用反复平方快速求幂。
伪代码1:
变量说明:
\[\begin{aligned}
&POWER(x,n) \\
&~~~~~~y\leftarrow 1 \\
&~~~~~~while~~~n>0 \\
&~~~~~~~~~~~~if~~~n~~~is~~~odd \\
&~~~~~~~~~~~~~~~~~~y\leftarrow y\times x \\
&~~~~~~~~~~~~x\leftarrow x\times x \\
&~~~~~~~~~~~~n\leftarrow \frac{n}{2}\\
&~~~~~~return~~~y
\end{aligned}
\]
C++解答:
constexpr auto power(int x, unsigned n) noexcept {
long y = 1, p = x;
while (n) {
if (n & 1)
y *= p;
p *= p;
n >>= 1;
}
return y;
}
Rust解答:
pub fn power(x: i32, mut n: u32) -> i64 {
let (mut y, mut p) = (1i64, x as i64);
while n > 0 {
if n & 1 != 0 { y *= p; }
p *= p;
n >>= 1;
}
y
}
4. 自我测试
伪代码实践:
N/A
LeetCode选荐:
N/A
让每一天足够精致,期待与您的再次相遇! ^_^

浙公网安备 33010602011771号