zoukankan      html  css  js  c++  java
  • [知识点] 6.2 快速幂

    总目录 > 6 数学 > 6.2 快速幂

    前言

    很早就知道的一个知识点了,应用场景很多,很实用。

    子目录列表

    1、概念

    2、算法描述

    3、具体思路

    4、代码

    5、应用

    6.2 快速幂

    1、概念

    快速幂,学名为二进制取幂(Binary Exponentiation),是一个在 O(log n) 时间内计算 a ^ n 的算法,对于 n 很大的情况下能大幅提高程序效率。不仅如此,它还可以应用在任何具有结合律的运算中。

    2、算法描述

    计算 a 的 n 次方,暴力算法即直接使用 for 循环进行 n 次相乘,时间复杂度为 O(n),当 n 较大时,显然不再适用。而快速幂算法利用指数能够进行分割来降低复杂度,已知 a ^ (b + c) = (a ^ b) * (a ^ c),a ^ (2 * b) = (a ^ b) ^ 2,那么,我们是否可以将较大的 n 进行拆分来计算呢?举个例子:

    3 ^ 13 = 3 ^ (1101)2 = (3 ^ 8) * (3 ^ 4) * (3 ^ 1)

    根据幂数的结合律,我们将其拆分成若干个 2 的次方数,比如上述例子 13 = 8 + 4 + 1,又可以通过计算得到 3 ^ 1 = 3, 3 ^ 2 = (3 ^ 1) ^ 2 = 9, 3 ^ 4 = (3 ^ 2) ^ 2 = 81, 3 ^ 8 = (3 ^ 4) ^ 2 = 6561,将其相乘即可。

    不难看出,快速幂是一种倍增思想的算法。原式被分解成 a 的 2 ^ k 次幂的序列,我们从 a ^ 1 开始通过倍增一一求出序列各数的值,其时间复杂度显然为 O(log n)。

    3、具体思路

    上一节提到的位运算(请参见:6.1 位运算与进位制),这里便是其很好的一个运用场景。在拆分幂数时,显然使用二进制要比十进制来得轻松。以上面的例子进行描述:

    > 初始结果为 1,初始倍增数为 3 ^ 1,13 的二进制为 (1101)2

    > 当前最低位为 1,对应 3 ^ 1,结果乘上 3 ^ 1 变成 3,倍增数倍增一次变成 3 ^ 2,(1101)2 右移一位变成 (110)2

    > 当前最低位为 0,对应 0 * 3 ^ 2,结果不变,倍增数倍增一次变成 3 ^ 4,(110)2 右移一位变成 (11)2

    > 当前最低位为 1,对应 3 ^ 4,结果乘上 3 ^ 4 变成 3 ^ 5,倍增数倍增一次变成 3 ^ 8,(11)2 右移一位变成 (1)2

    > 当前最低位为 1,对应 3 ^ 8,结果乘上 3 ^ 8 变成 3 ^ 13,倍增数倍增一次变成 3 ^ 16,(1)2 右移一位变成 (0)2,结束,退出循环

    4、代码

    int pow(int a, int b) {
        int o = a, res = 1;
        while (b) {
            if (b & 1) (res *= o) %= MOD;
            (o *= o) %= MOD;
            b >>= 1;
        }
        return res;
    }

    代码展示的是最为常见的应用 —— 模意义下直接求幂

    根据费马小定理(请参见:6.4.2 费马小定理与欧拉定理),如果 b 是一个质数,可以直接计算 a ^ (b mod (MOD - 1))

    5、应用

    除了直接求幂,还可以用于计算斐波那契数,多次置换等等。此处暂略。

  • 相关阅读:
    iOS 9适配技巧(更新版)
    VC/MFC 在ListCtl 控件中随鼠标移动提示单元格信息
    VC++ 编译libcurl 支持SSL,GZIP
    qt使用动态库(DLL)
    解决修改mysql的data_dir所引发的错误
    Mybatis实战之TypeHandler高级进阶
    Mybatis实战之自定义TypeHandler处理枚举
    shell编程其实真的很简单(五)
    shell编程其实真的很简单(四)
    shell编程其实真的很简单(三)
  • 原文地址:https://www.cnblogs.com/jinkun113/p/13333897.html
Copyright © 2011-2022 走看看