zoukankan      html  css  js  c++  java
  • 快速幂

    快速幂的目的是做到快速求幂,假设我们要求a^b,按照朴素算法就是把a连乘b次,这样一来时间复杂度是O(b)也即是O(n)级别,快速幂能做到O(logn),快了很多。

    当b=11时,b的二进制:1011,

      

    &运算通常用于二进制取位操作,例如一个数 & 1 的结果就是取二进制的最末位。还可以判断奇偶x&1==0为偶,x&1==1为奇。

    幂运算是非常常见的一种运算,求取a^n,最容易想到的方法便是通过循环逐个累乘,其复杂度为O(n),这在很多时候是不够的,所以我们需要一种算法来优化幂运算的过程。

    一、快速幂——反复平方法

    该怎样去加速幂运算的过程呢?既然我们觉得将幂运算分为n步进行太慢,那我们就要想办法减少步骤,把其中的某一部分合成一步来进行。

    比如,如果n能被2整除,那我们可以先计算一半,得到a^(n/2)的值,再把这个值平方得出结果。这样做虽然有优化,但优化的程度很小,仍是线性的复杂度。

    再比如,如果我们能找到2^k == n,那我们就能把原来的运算优化成((((a^2)^2)^2)...),只需要k次运算就可以完成,效率大大提升。可惜的是,这种条件显然太苛刻了,适用范围很小。不过这给了我们一种思路,虽然我们很难找到2^k == n,但我们能够找到2^k1 + 2^k2 + 2^k3 +......+ 2^km == n。这样,我们可以通过层层递推,在很短的时间内求出各个项的值。可是又有新的问题出现了,我们并不清楚k1、k2...km具体的值是多少,对于不同的n,有不同分法,有没有一种规则能把这些分法统一起来。

    我们都学习过进制与进制的转换,知道一个b进制数的值可以表示为各个数位的值与权值之积的总和。比如,2进制数1001,它的值可以表示为10进制的1*2^3 + 0*2^2 + 0*2^1 + 1*2^0,即9。这完美地符合了上面的要求。可以通过2进制来把n转化成2^km的序列之和,而2进制中第i位(从右边开始计数,值为1或是0)则标记了对应的2^(i - 1)是否存在于序列之中。譬如,13为二进制的1101,他可以表示为2^3 + 2^2 + 2^0,其中由于第二位为0,2^1项被舍去。

    如此一来,我们只需要计算a、a^2、a^4、a^8......a^(2^km)的值(这个序列中的项不一定都存在)并把它们乘起来即可完成整个幂运算。借助位运算的操作,可以很方便地实现这一算法,其复杂度为O(logn)。

    typedef long long ll;
    ll quick_pow(ll a, ll n)//a^n
    {
        ll re = 1;
        while(n != 0)
        {
            if(n & 1)//判断n的最后一位是1还是0
                re *= a;
            a = (a * a);//将a平方,即把a^(2^i)变为a^(2^(i + 1))
            n >>= 1;//n右移一位,舍去n的最后一位
        }
        return re;
    }

     

     

     

  • 相关阅读:
    .net 自带的oracleclient 的一点小问题
    重新感受Windows 的激情
    三点定面的算法实现
    回归.NET的世界
    .NET 基础题, 可以做面试题, 不断更新 20111
    C#根据字符串生成唯一的数字
    最近看的书
    代码中的注释, 需要面向功能注释,而非使用注释
    html 页面嵌入 Silverlight , Silverlight控件覆盖悬浮HTML元素的解决方法.
    gitlab clone或者pull 仓库
  • 原文地址:https://www.cnblogs.com/UalBlog/p/10636850.html
Copyright © 2011-2022 走看看