zoukankan      html  css  js  c++  java
  • 初学 快速幂 的理解

      博客停了差不多三个月, 虽然这一段时间在学算法, 但从来没有写博客。 今天看了一上午的快速幂,突然想写写博客, 增加一下自己的记忆!这个博文知识简单介绍一下算法中取余的原因


     

     1 至于快速幂的概念不详细记录了。当我们想求a的b次幂对c取余时,我们会直接想到用这个算法:

    int ans = 1;
    
      for( i  = 1; i <= b; i++)
    
      {
    
        ans = ans * a;
    
      }
    
      ans %= c;

      这个算法的时间复杂度体现在for循环中,为O(b).这个算法存在着明显的问题,如果a和b过大,很容易就会溢出。因此需要用到离散数学知识(该知识点我也没学过,度娘教的^_^)


     

     

      定理1:

      

     


     

     2 由上面的公式可以推出: 

        

         把a看成 a * 1, 故由定理1可得出上面的公式。由此得到改进版本:

      int ans = 1; 
    
      a = a % c; //加上这一句
    
      for(int i = 1;i<=b;i++)
    
      {   
    
      ans = (ans * a) % c;//这里再取了一次余 
    
      } 
    
      ans = ans % c;

    这个算法在时间复杂度上没有改进,仍为O(b),不过已经好很多的,但是在c过大的条件下,还是很有可能超时,所以,我们推出以下的快速幂算法。


     

    3   快速幂算法依赖于以下明显的公式,我就不证明了,很简单理解。

      

        


    4    由此得到改进版本:

      int ans = 1;
    
      a = a % c;
    
       if(b%2==1) 
    
      ans = (ans * a) mod c; //如果是奇数,要多求一步,可以提前算到ans中
    
      k = (a*a) % c; //我们取a2而不是a
    
      for(int i = 1;i<=b/2;i++)
    
      { 
    
        ans = (ans * k) % c;
    
      } 
    
      ans = ans % c;

     

     5  我们可以看到,我们把时间复杂度变成了O(b/2).当然,这样子治标不治本。但我们可以看到,当我们令k = (a * a) mod c时,

       状态已经发生了变化,我们所要求的最终结果即为(k)^b/2 mod c而不是原来的a^b mod c,所以我们发现这个过程是可以迭代下去的。

     ((迭代就是把这一次算的值作为下一次循环的初始值,所以可以更简化该算法))

       当然,对于奇数的情形会多出一项a mod c,所以为了完成迭代,当b是奇数时,我们通过  ans = (ans * a) % c;来弥补多出来的这一项,

       此时剩余的部分就可以进行迭代了。   形如上式的迭代下去后,当b=0时,所有的因子都已经相乘,算法结束。于是便可以在O(log b)的时间内完成了。

       于是,有了最终的算法:快速幂算法。

     ((说实话, 我对这个简化有点糊涂,关于在O(log b)的时间内就可以完成, 就假装懂了吧, 以后慢慢理解吧))


     6

     int ans = 1;
    
       a = a % c;
    
      while(b>0)
    
      {   
    
        if(b % 2 == 1) 
    
        ans = (ans * a) % c;
    
        b = b/2; 
    
        a = (a * a) % c; 
    
      } 

     


     

     

     7 将上述的代码结构化,也就是写成函数:

    int PowerMod(int a, int b, int c)
    
      { 
    
        int ans = 1;
    
        a = a % c;
    
        while(b>0) 
    
        {   
    
          if(b % 2 = = 1) 
    
          ans = (ans * a) % c;
    
           b = b/2; 
    
          a = (a * a) % c; 
    
          }
    
      return ans;
    
      }

     

      


     

     

          这就是最后的优化代码了。以上内容是抄袭的, 只不过自己又写了一遍。如果看不懂我写的的可以点下面网址:

      http://wenku.baidu.com/link?url=PdtuRuYTZSIfAC3TZCiHSx3fk7cEn3yuZBiYwbx-b7h_TOxNyOQtNOaUepEmxw56jhnPePqAdebOH6QL- pvmhFCYYdzGhYRneUM_oZTpxwO

       有关于快速幂的算法的推导,还可以从另一个角度来想。我就不介绍了。

  • 相关阅读:
    python 全栈基础作业题
    计算机基础之二:操作系统的发展史
    计算机基础系列之一:计算机硬件概述
    饼图
    折线图
    win_diy_monkey demo
    csv,Excel
    uiautomator2
    win ui自动化测试
    html
  • 原文地址:https://www.cnblogs.com/lj-1568/p/4754336.html
Copyright © 2011-2022 走看看