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竞赛中题中涉及到过此类赛题,且有结果取模问题,一篇很有价值的文章

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

         举例  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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章