快速冪,就是快速算底數的n次冪。其時間復雜度為 O(logN), 與朴素的O(N)相比效率有了極大的提高。
朴素算法
在要求算出一個數字的n次冪時,最容易想到的便是朴素的循環累乘:
int normalPower(int base, int exponent) {
while (exponent > 0) {
base *= base;
--exponent;
}
return base;
}
很明顯,這種方法的時間復雜度為O(N);
快速冪算法
根據二進制的性質以及編程語言中方便的與運算符&
和移位運算符>>
,有人提出了快速冪的算法,其時間復雜度為O(logN)。對這兩個操作符不明白的同學可以先看文末的簡述。
1.快速冪思想
例如計算ab這樣一個數,我們指數b以轉換二進制的形式進行分解,將其寫成二進制中每一位乘上該位的權重(從右往左,第i位的權為2i-1)。
例如:a13 = a2^0+2^2+2^3 = a2^0a2^2a2^3
2.快速冪實現
在這里我們先給出快速冪實現的代碼,方便后續進行對照講解
int fastPower(int base, int exponent) {
int sum = 1;
while (exponent != 0) {
if ((exponent & 1) != 0) {
sum *= base;
}
exponent = expnonent >> 1; // 對指數進行移位
base *= base; // 讓base的次冪以2的倍數增長
}
return sum;
}
需要額外注意的是,&
操作符的運算符低於>
之類的比較運算符,也低於==
和!=
運算符。
3.快速冪講解
首先可以看到,循環的終止條件為指數e為0,且每次循環e都會右移一位,而自然數N的二進制長度為log2N,因此這個循環至多遍歷log2N次。即它的時間復雜度為O(logN)
。
我們在每次指數右移的同時,讓底數base=base*base。這樣一來,第一次循環結束后base的大小變為原來的2=21次方倍,第二次后變為原來的21*21=22次方倍...最終,我們在第n次循環中sum所乘的base總是base2^(n-1)。保證了算法的正確性。而每次base2^(n-1),總能在下一次的循環中利用到base2^n的計算中,減少了程序的時間消耗與空間消耗。
假設我們輸入了fastPower(bbasese, 13)
這樣一個函數,那么按照上面的定義,13應該是被理解為二進制串1101,在每次開始都進行和1相與,為1時才進行sum和bbasese的相乘,聯系上一段話,我們不難推斷出我們能夠按照base13 = base2^0+2^2+2^3 = base2^0base2^2base2^3的順序計算。
快速冪預備知識
1.二進制
相信大家都知道二進制的原理,這里我們主要用到十進制與二進制相互轉換的原理。
舉個例子,6的二進制是110,那么6便可以標示成22+21。
2.與運算符&
這是一個二元運算符,返回左右兩數以二進制形式相與后的結果。例如x & 1 == 1
則表示x為奇數,x & 1 == 0
則為偶數。
3.移位運算符>>
顧名思義,這是令一個數的二進制形式移位的操作符。該操作符指向右邊,因此是右移,例如1011>>1 = 101
。相似的,還有左移用的操作符<<
,不過這里用不上。