快速幂 迭代算法 LeetCode官方题解超级无敌简单版

递归的方式大家可以看看官方题解,官方写得挺好懂:
LeetCode 50. Pow(x, n) 官方题解
然后呢,官方的迭代方式写得有点复杂,我写一下我的理解,应该会简单一点(啰嗦亿点

首先呢我们来算算 x 77 x^{77} x77。我们本能的想, x 77 x^{77} x77就是将77个 x x x相乘。那么有没有更快的方法呢?

77个 x x x相乘,其实就是 x 1 + 1 + 1 + ⋯ + 1 ( 一 共 77 个 1 ) x^{1+1+1+\cdots+1}(一共77个1) x1+1+1++1(771)。指数一直加1当然可以得出77,但是1+4+8+64也可以得出77,而且比单独的加法快很多(当幂运算指数越大,这种方式效率越高)但是为什么 77 = 1 + 4 + 8 + 64 77=1+4+8+64 77=1+4+8+64呢?拉回我们的问题,我们可以知道,等式:
x 77 = x 1 × x 4 × x 8 × x 64 x^{77}=x^{1} \times x^{4} \times x^{8} \times x^{64} x77=x1×x4×x8×x64成立。但是为什么会成立呢?

我们将77分解成二进制看一下:
( 77 ) 10 = ( 1001101 ) 2 (77)_{10} = (1001101)_2 (77)10=(1001101)2可以发现,这些指数 1,4,8 和 64,恰好就对应了二进制表示 ( 1001101 ) 2 (1001101)_2 (1001101)2中的每个 1!这是为什么呢?因为它是二进制呀:

我们知道,二进制就是满二进一,第 n n n个二进制位的数值就表示有多少个 2 n − 1 2^{n-1} 2n1。(如果不理解,可以代入我们熟悉的十进制思考一下) 同时因为二进制只有0或1,所以如果二进制为位0,就代表有0个 2 n − 1 2^{n-1} 2n1

所以 ( 1001101 ) 2 (1001101)_2 (1001101)2就表示:

77有一个 2 0 2^0 20(第一个二进制位是1),有0个 2 1 2^1 21(第二个二进制位为0),有一个 2 2 2^2 22(第三个二进制位是1),同理,有一个 2 3 2^3 23 2 7 2^{7} 27(第4和第8个二进制位是1)。

所以77的二进制位的意思就是: 77 = 1 + 4 + 8 + 64 77=1+4+8+64 77=1+4+8+64

最终我们知道: x 77 = x 1 × x 4 × x 8 × x 64 x^{77}=x^{1} \times x^{4} \times x^{8} \times x^{64} x77=x1×x4×x8×x64

也就是: x 77 = x 2 0 × x 2 2 × x 2 3 × x 2 7 x^{77}=x^{2^0} \times x^{2^2} \times x^{2^3} \times x^{2^7} x77=x20×x22×x23×x27。我们写代码就要用这个式子,这样子方便我们循环算出指数。

有了这个思路,我们就可以写出迭代版的快速幂算法了。大家可以直接看代码,但是如果还没有思路,或者代码看不懂,可以看一下下面的说明:

把77没有的二进制位补上,即:
77 = 2 0 + 2 2 + 2 3 + 2 6                                                                                = 1 × 2 0 + 0 × 2 1 + 1 × 2 2 + 1 × 2 3 + 0 × 2 4 + 0 × 2 5 + 1 × 2 6 77=2^0+2^2+2^3+2^6 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\\ =1\times2^0+ 0\times2^1+ 1\times2^2+ 1\times2^3+ 0\times2^4+ 0\times2^5+ 1\times2^6 77=20+22+23+26                                                                              =1×20+0×21+1×22+1×23+0×24+0×25+1×26
写成最初的幂运算:
x 77 = x 1 × 2 0 + 0 × 2 1 + 1 × 2 2 + 1 × 2 3 + 0 × 2 4 + 0 × 2 5 + 1 × 2 6                                       = x 1 × 2 0 × x 0 × 2 1 × x 1 × 2 2 × x 1 × 2 3 × x 0 × 2 4 × x 0 × 2 5 × x 1 × 2 6 x^{77}= x^{ 1\times2^0+ 0\times2^1+ 1\times2^2+ 1\times2^3+ 0\times2^4+ 0\times2^5+ 1\times2^6 } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \\=x^{1\times2^0}\times x^{0\times2^1}\times x^{1\times2^2}\times x^{1\times2^3}\times x^{0\times2^4}\times x^{0\times2^5}\times x^{1\times2^6} x77=x1×20+0×21+1×22+1×23+0×24+0×25+1×26                                     =x1×20×x0×21×x1×22×x1×23×x0×24×x0×25×x1×26
思路:写成这样子我们发现,我们可以用循环,每一次都将指数翻倍(也就是将上一个项平方),然后通过判断二进制的最低位是否为1,来判断最终的式子是否要乘上当前循环的 2 n − 1 2^{n-1} 2n1的值。

代码:

/**
x为底数,N为指数。计算x^N
*/
double quickMul(double x, long N) {
    double ans = 1.0;
    // 在对 N 进行二进制拆分的同时计算答案
    while (N > 0) {
        /*
        当二进制位为0时,表示有0个2^n-1
        此时我们将x平方,但是不乘在算式中
        	(注意此时的x经过循环已经不是最初的x了,它可能是x^4,平方后就是x^8)
        如果 N 二进制表示的最低位为 1,那么与ans相乘
        这一步作用就是:
        	通过循环的将x^1,x^4,x^8,x^64这几个需要相乘的数乘在一起
        */
        if (N % 2 == 1) {
            ans *= x;
        }
        // 通过前面的文字分析可以知道,每一次循环都要将底数平方(指数翻倍)
        x *= x;
        // 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位是否为1即可
        N /= 2;
    }
    return ans;
}

public double myPow(double x, int n) {
    long N = n;
    // 如果求负数幂,则等价于求倒数: 1/(x^-n)
    return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值