算法|快速幂

完成阅读您将会了解快速幂的:

  1. 算法思想
  2. 实现步骤
  3. 实践范例(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. 实现步骤

  1. 将结果y初始化为1;
  2. 如果指数n为奇,将当前底数x乘进结果;
  3. 将底数平方;
  4. 将指数除以2;
  5. 若指数仍然大于零则从第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

让每一天足够精致,期待与您的再次相遇! ^_^

posted @ 2021-07-06 19:38  我的名字被占用  阅读(259)  评论(0)    收藏  举报