算法练习—快速幂

算法练习—快速幂

   首先说下,快速幂解决的是什么问题,核心问题是解决计算机 “受不了的数”的问题。例如下面这道题:
实现 pow(x, n) ,即计算 x 的整数 n 次幂函数。

1.在没有学习快速幂之前我大脑里只有一个思路,暴力解决。

import java.util.*;
class Solution {
    public double myPow(double x, int n) {

        
        if(x==0) return 0;

        if(n<0){
            x=1/x;
            n=-n;
        }

        double res=1.0;
        for(int i=0;i<n;i++){
            res*=x;
        }

        return res;


    }
}
   这样解是可以得到答案的,但是一般都会报超出时间限制,因为当n无限增大时,需要循环的次数呈指数级上升,会达到一个非常恐怖的次数。

2.1什么是快速幂算法

   快速幂算法又称为二进制取幂(Binary Exponentiation),能够大幅度的减少计算步骤,从而提升运算速度,是一个在logn的时间内计算 的小技巧,而暴力的计算需要 n 的时间。

2.2代码展示

import java.util.*;
class Solution {
    public double myPow(double x, int n) {
    
        if(n==0) return 1;
        #当测试数据n=-2147483648时执行n=−n会因越界而赋值出错。
        #解决方法是先将n存入long变量b后面用b操作即可
        long b=n;
        if(b<0){
            x=1/x;
            b=-b;
        }
        double res=1.0;
        while(b>0){
        	#if((b&1)==1)位运算等同于if(b%2==1)
            if((b&1)==1) res=res*x;
            x=x*x;
            #b>>=1位运算等同于b/=2
            b>>=1;
        }

        return res;
    }
}

3例题展示

在基本了解了快速幂算法后我们来看一道例题:
我们称一个数字字符串是 好数字 当它满足(下标从0开始偶数下标处的数字为偶数且奇数下标处的数字为质数 (2,3,5 或 7)。
比方说,"2582" 是好数字,因为偶数下标处的数字(2 和 8)是偶数且奇数下标处的数字(5 和 2)为质数。但 "3245" 不是好数字,因为3在偶数下标处但
不是偶数。给你一个整数 n ,请你返回长度为 n 且为好数字的数字字符串总数 。由于答案可能会很大,请你将它对10^9 + 7取余后返回 。一个数字字符串是
每一位都由0到9组成的字符串,且可能包含前导0 。
3.1例题分析
   一开始在看到这个题是我一头雾水,完全不知道从哪里下手,应该是我比较蠢,根本没有想到这道题
的关键所在。其实大家仔细分析一下,可以发现,在这道题中,对于任意一个数字如果要满足好数字特
征,那么他的偶数位只能为(0,2,4,6,8),奇数位只能为(2,3,5,7),而对于一个n位数字,
他的偶数位一共为(n+1)/2位,奇数位为n/2位。所以对于一个n位数字,满足为好数字的总数为:
[5*(n+1)/2]*[4*n/2]。
如果n为奇数则:[5^(n+1)/2]*[4^n/2]=5*20^n/2。
如果n为偶数则:[5^(n+1)/2]*[4^n/2]=20^n/2。
其实分析到现在这道题已经完全变成求某个数的指数幂的运算,不过我们还是要注意一些细节,下面我
们来看代码展示。
3.2暴力解决
class Solution {
    public int countGoodNumbers(long n) {

      int mod=1000000007;
      long res=(n&1)==1?5:1,power=n/2,base=20;

      for(int i=0;i<n/2;i++){
          res=res*base;
      }

      return (int)(res%mod);

    }
}
    这样解题虽然逻辑上没有问题,但是一定不会编译通过,因为当n无限大时,计算结果会远大于long
数据所能表示的最大数字,会造成数据溢出,而且此时循环次数也非常大,即使没有数据溢出也会超出时
间限制。
3.3取模定理
    取模运算解决的多个大数相乘所得结果过大(计算机不支持)而取不了后几位的问题,取模定理我
也是第一次听,看了之后发现是真的牛,不愧是数学定理。
(a + b) % p = (a % p + b % p) % p (1)
(a - b) % p = (a % p - b % p ) % p (2)
(a * b) % p = (a % p * b % p) % p (3)
 a ^ b % p = ((a % p)^b) % p (4)
    这里仅需看这里面的(3),(a * b) % p = (a%p * b%p) % p,这个就厉害了,乘积的取模
等于各个因子取模相乘然就在取模,相当于把数都控制在 p-1 位,这计算数量就超级小了,有木有~
class Solution {
    public int countGoodNumbers(long n) {

      int mod=1000000007;
      long res=(n&1)==1?5:1,power=n/2,base=20;

      for(int i=0;i<n/2;i++){
          res=res*base%mod;
      }

      return (int)(res%mod);

    }
}
     加上取模定理之后其实已经不会数据溢出了,但是还是会报超出时间限制,取模定理仅仅是将数据都
给控制在一定位数以内,让数可以计算出来,但是并没有简化计算次数。要是有简化计算步骤的算法就
更好了,接下来就可以使用能够缩短计算次数的快速幂算法。
3.4快速幂算法–最终方案
class Solution {
    public int countGoodNumbers(long n) {

      int mod=1000000007;
      long res=(n&1)==1?5:1,power=n/2,base=20;

      while(power>0){
          if((power&1)==1) res=res*base%mod;

          base=base*base%mod;

          power>>=1;
      }

      return (int)res;

    }
}
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路上阡陌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值