Pyhton 快速幂和快速乘法

面试题 1+2+...+n 不用for循环等,题解中方法快速幂和快速乘法的知识盲点补充内容。

快速幂:就是快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。

求a的b次方幂。(a=3,b=11) 

     11 = 1*2^3+0*2^2+1*2^1+1*2^0=0b(1011)

     a^{11} = a^8*a^2*a^1=a^{0b 1011}=a^{2^0}*a^{2^1}*a^{2^3}

做法:将b转成二进制,用i去循环b中的每一位,若该位置为1,那么就乘以a^{2^i}。直至b为0。

def exponential_calculation(a,b): #迭代版本
    ans = 1
    while(b):
        if( b&1 ) :   #如果b的当前末位为1,则相乘 
            ans *= a  #ans乘上当前的a,决定是否*(a^2);*(a^4);*(a^8)
        a *= a        #a自乘,构造 a^2 a^4 a^8 a^16..
        b >>= 1       #b往右移一位,判断每个位置
    return ans
def t(a,b): ##递归版本
    if not b :return 1 #while结束条件
    if b&1 : # while 里面的if判断
        return a*t(a*a,b>>1)
    else:
        return 1*t(a*a,b>>1)

思考:【1】为什么b&1返回的就是b的最后一位是0还是1?(利用b&1来判断b的奇偶性,b的最后一位是1 奇数反之偶数)

不是与1做按位与运算,而是与 1 = 0b0001做按位与运算。

假设  b(5) = 0b0101  &  0b0001(1)

             \frac{\begin{matrix} 0 & 1 & 0 & 1 \\ 0 & 0& 0 & 1 \end{matrix}}{\begin{matrix}0 & 0 & 0 & 0 \end{matrix}} 

可以看出 除了末位之外的位与0做按位与肯定是0,所以只看最后一位是什么,如果是1则1,是0则0。那么每次就可以查看b的最后一位,并且可以利用b&1来判断b的奇偶性,b的最后一位是1 就是 奇数反之偶数。

【2】ACM竞赛中题中涉及到过此类赛题,且有结果取模问题,一篇很有价值的文章

除了上面的这种公式的思想外,还有另外一种思考方式[二分法角度]。下面的二分法角度思想摘自:此链接

x^n = x^{n/2}*x^{n/2}=(x^2)^{n/2}  

当 n 为偶数的时候,x^n = x^{n//2}*x^{n//2}=(x^2)^{n//2}     "//"整除的意思 向下取整

当 n 为奇数的时候,x^n = x* x^{n//2}*x^{n//2}=x*(x^2)^{n//2}

def exponential_calculation(a,b): #迭代版本
    ans = 1
    while(b):
        if( b & 1 ) :   #判断奇偶性,而不是判断最后一位是0还是1
            ans *= a    #奇数 多乘以一个 a
        a *= a          #a自乘,构造 a^2 a^4 a^8 a^16..
        b >>= 1         #b往右移一位 b/2 b/4 b/8 b/16 直到b为0
    return ans

快速乘法:类似于上面的快速乘法,只是把乘号改成加号。

         举例  a*b (3*10)    ----->>   a*(0b1010)=a*(2^3+2^1)=a*2^3+a*2^1

def t(a,b): #迭代
    ans = 0 
    while(b):
        if b&1:
            ans += a # 实现对应位置相加
        a += a ## 实现 a*2 a*4 a*8 
        # a <<= 1 效果同上 
        b >>= 1
    return ans

def t(a,b): ##递归版本
    if not b : return 0 #while结束条件
    if b&1 : # while 里面的if判断
        return a+t(a+a,b>>1)
        # return a+t(a<<1,b>>1)
    else:
        return 0+t(a+a,b>>1)

在上面的问题中,没有考虑溢出的问题。有人说python不用考虑溢出,又有人说python的确会有溢出问题。[我现在也没发现特别好的文章来说这个点,如果有再补充把]

在c++等程序语言中,通常利用求余的方法来解决溢出问题,上面的ACM竞赛题也是。上面文章链接有分析就不写了。

参考:

【1】https://zhuanlan.zhihu.com/p/95902286

【2】https://blog.csdn.net/Harington/article/details/87602682

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Foneone

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

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

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

打赏作者

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

抵扣说明:

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

余额充值