快速幂算法

1 简介

​ 快速幂(平方求幂)算法,是一种计算乘方的简单有效的算法,它可以在O(log n)的时间复杂度下进行求幂操作。快速幂算法的数学表示如下:

an={an1aif n is oddan2an2,if n is even but not 01,if n = 0

2 分析

​ 为什么快速幂算法能够在O(log n)的时间复杂度下工作呢?

​ 我们以210为例进行分析:

方法1:最朴素的想法,22=442=8,..., 一步一步算,共进行了9次乘法。

​ 这样算无疑太慢了,尤其对计算机的CPU而言,每次运算只乘上一个个位数,无疑太屈才了。这时我们想到,也许可以拆分问题。

方法2:先算2的5次方,即22222,再算它的平方,共进行了5次乘法。

​ 但这并不是最优解,因为对于“2的5次方”,我们仍然可以拆分问题。

方法3:先算22得4,则2的5次方为442,再算它的平方,共进行了4次乘法。

​ 模仿这样的过程,我们得到一个在O(logn)时间内计算出幂的算法,也就是快速幂

3 算法实现

递归实现:

public int qpow(int a, int n) {
    if(n == 0) {
        return 1;
    }else if(n % 2 == 1) {
        return qpow(a, n - 1) * a;
    } else {
        int temp = qpow(a, n / 2); // 注意不能直接return qpow(a, n / 2) * qpow(a, n / 2), 否则会退化为O(n)。
        return temp * temp;
    }
}

非递归实现

public int qpow(int a, int n) {
    int ans = 1;
    while(n != 0) {
    	if((n & 1) != 0) { // 判断二进制数的末位为0还是为1
        	ans *= a;
    	}
    	n >>= 1; // 将二进制数右移一位,也相当于/2
    	a *= a;   
    }
    return ans;
}

​ 非递归形式比较难以理解,作如下解释(以210为例):

我们将幂指数n以二进制形式表示,则210=2(1010)2 ,我们可以将其拆成2(1000)22(10)2。对于任意整数,我们都可以做类似的拆分。

最初ans为1,然后我们一位一位算:

1010的最后一位是0,所以a1这一位不要。然后1010变为101,a变为a2

101的最后一位是1,所以a2这一位是需要的,乘入ans。101变为10,a再自乘。

10的最后一位是0,跳过,右移,自乘。

然后1的最后一位是1,ans再乘上a8。循环结束,返回结果。

针对如上所述过程,我们总结如下:

  • 如果幂指数二进制表示的末位数为1,则需要将此时的a乘入ans中;

  • 如果末位数为0, 则无需将a乘入ans,但是需要让a=a2

a依次变为a1,a2,a4,a8,....,只要对应的二进制末位数为1就将其乘入到ans中,否则就不乘入。这样对于an的求解,我们只需做log2n次运算即可,从而达到O(logn)的时间复杂度。

posted @   Xiao·Tong  阅读(367)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示