快速冪


超級詳細的基礎算法和數據結構合集:
https://blog.csdn.net/GD_ONE/article/details/104061907

摘要

本文主要介紹快速冪算法,快速冪雖然代碼簡單,但是往往會與其他算法相結合,很重要。

引言

當我們計算 nkn^k時,常用的做法是對nn連乘kk次, 但如果kk特別大,假如k=1e6k = 1e6, 如果仍然對n1e6n連乘1e6次的話,時間消耗就太大了。那麼我們如何
在短時間內求出一個數的kk次方呢。

nkn^k

我們可以考慮對樸素方法進行優化。
1:當我們計算得到n2n^2時, 我們可以直接使用n2n^2連乘k/2k/2次。 這樣做時間複雜度變爲了O(n/2)O(n/2)
2:有人可能會問,我們既然可以用n2k/2n^2連乘k/2次,爲什麼不用n4n^4連乘k/4k/4次呢,當然可以這樣做之後時間複雜度變爲了O(n/4)O(n/4);
3 : 我們當然也可以n8,n16...n^8,n^{16}...連乘
4:所以我們可以用:n1n2n4n8...npn^1 * n^2 * n^ 4 *n^8...n^p
快速冪就是類似的思想。

快速冪

先舉個例子:
311=31313131313131313131313^{11} = 3^1* 3^1 *3^1*3^1*3^1*3^1*3^1*3^1*3^1*3^1*3^1
11101111的二進制表示爲: 1011
怎麼把一個二進制數轉化爲十進制數呢?
計算過程是:11=120+121+022+123=1+2+0+811 = 1*2^0 + 1 * 2^1 + 0 * 2^2+ 1*2^3 = 1 + 2 + 0 + 8
我們可以發現:如果將最開始求3113^{11}變爲:311=313230383^{11} = 3^1 * 3^2 * 3^0*3^8, 計算量將會大大減少,原本需要乘11次,現在只需要乘4次。

另外,我們需要判斷二進制數的某一位是不是0,我們可以使用位運算方便的解決該問題。

快速冪代碼:

public static int qmi(int a, int b){ //求 a^b
	int res = 0; // res保存結果
	while(b != 0){
		if((b & 1) == 1){ //如果k的二進制數的最後一位是 1。 比如1011 & 1 = 1
			res = (res + a) % mod;
		}
		a = a * a % mod;//得到 a^1, a^2, a^4, a^8, .....
		b = b >> 1; //將b右移一位,去掉最低位。爲了開始判斷下一位。
	}
	return res;
}

代碼很簡單,多看幾遍就懂了。如果對位運算不熟悉可以翻看之前的博客。

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