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

 

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