日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java位运算求幂,程序员必学:快速幂算法

發(fā)布時(shí)間:2025/3/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java位运算求幂,程序员必学:快速幂算法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前陣子,有小伙伴在我B站的算法教程底下留言

小伙伴們有任何疑問或者希望我解說任何內(nèi)容,都可以在我的小我私家B站或民眾號(hào)(xmg_mj)留言哦,我會(huì)盡我最大能力、只管抽時(shí)間去寫文章\錄視頻來回應(yīng)人人。

關(guān)于快速冪

實(shí)在快速冪相關(guān)的問題,是加入算法競(jìng)賽(NOI、ACM等)的小伙伴必須要掌握的一小塊基礎(chǔ)內(nèi)容。固然,就算你不設(shè)計(jì)加入算法競(jìng)賽,小我私家以為只要你是一名程序員,就必須要掌握快速冪算法。

在《計(jì)算機(jī)程序設(shè)計(jì)藝術(shù)》一書中就有提到快速冪算法,此書的英文名是The Art of Computer Programming,簡(jiǎn)稱TAOCP。

TAOCP出自Donald Ervin Knuth先輩之手。Knuth先輩是在計(jì)算機(jī)領(lǐng)域成就頗豐的著名科學(xué)家,是著名的KMP算法的發(fā)明人之一,在1974年獲得“計(jì)算機(jī)領(lǐng)域的諾貝爾獎(jiǎng)”:圖靈獎(jiǎng)(昔時(shí)他才36歲)。現(xiàn)在TAOCP已經(jīng)出書了第1、2、3、4A卷,憑據(jù)設(shè)計(jì),另有第4B、5、6、7卷未出書。第一卷首發(fā)于1968年,Knuth先輩今年是82歲高壽,聽說他設(shè)計(jì)在105歲之前完成這部巨著。

關(guān)于TAOCP,微軟創(chuàng)始人Bill Gates曾說過

If you think you’re a really good programmer… read (Knuth’s) Art of Computer Programming… You should definitely send me a resume if you can read the whole thing.

也許意思是:若是你以為自己是一位異常優(yōu)異的程序員,那就應(yīng)該閱讀Knuth的TAOCP;若是你能讀懂全部?jī)?nèi)容,可以直接給我發(fā)送一份簡(jiǎn)歷。聽說Knuth先輩的言辭加倍犀利:看不懂就別當(dāng)程序員了!不外TAOCP對(duì)于新手來說,閱讀難度簡(jiǎn)直對(duì)照大,書中的所有示例都使用了Knuth先輩自創(chuàng)的MIX匯編語(yǔ)言。

閱讀本文之前的提醒

今天就抽閑寫一篇文章來解說一下經(jīng)典的快速冪算法哈。不外要想徹底看懂本文,有幾個(gè)前提條件

熟悉算法中的2個(gè)基礎(chǔ)觀點(diǎn):時(shí)間復(fù)雜度、空間復(fù)雜度

若是你壓根沒聽過這2個(gè)觀點(diǎn),說明你的算法基礎(chǔ)完全為0,真的沒有在開頑笑!

可以向民眾號(hào)發(fā)送復(fù)雜度獲取相關(guān)教程

熟悉二進(jìn)制和十進(jìn)制的轉(zhuǎn)換

若是連這個(gè)都不熟悉的話,那你的編程基礎(chǔ)就真的需要好好補(bǔ)補(bǔ)啦

可以向民眾號(hào)發(fā)送進(jìn)制獲取相關(guān)教程

熟悉常見的位運(yùn)算操作

n & 1的效果是n最低二進(jìn)制位的值,也可以用于判斷n的奇偶性

求正整數(shù)n / 2,可以用位運(yùn)算取代:n >> 1

若是不明白上述操作的原理,可以向民眾號(hào)發(fā)送位運(yùn)算獲取相關(guān)教程

什么是冪(Power)?

眾所周知,x的n次冪,是指x的n次方,也就是n個(gè)x相乘,好比2的4次冪就是2 * 2 * 2 * 2。

為了簡(jiǎn)化形貌,后面x的n次冪,我就簡(jiǎn)化為x ^ n(本文中的 ^ 并不是按位異或的意思)

那若何通過編程求冪?假設(shè)只思量x、n是整數(shù)且n大于即是0的情形,最容易想到的方式如下所示(這里接納的編程語(yǔ)言是Java,但沒有涉及Java特殊的語(yǔ)法。以是就算你沒用過Java,也可以看懂)

int power(int x, int n) {

int result = 1;

while (n-- > 0) {

result *= x;

}

return result;

}

很顯然,這種方式的時(shí)間復(fù)雜度是O(n)、空間復(fù)雜度是O(1)

什么是快速冪?

所謂快速冪,就是用效率更高(時(shí)間復(fù)雜度更低)的方式求冪,可以將時(shí)間復(fù)雜度優(yōu)化至O(logn)。這里先容2種求解方式:遞歸、非遞歸

遞歸

憑據(jù)上圖中的等式,不難寫出以下代碼

int fastPower(int x, int n) {

if (n == 0) return 1;

int result = fastPower(x, n >> 1);

result *= result;

return (n & 1) == 0 ? result : result * x;

}

這個(gè)方式的時(shí)間、空間復(fù)雜度都是O(logn)。

那若何剖析出這個(gè)方式的復(fù)雜度呢?

若是你的算法功底對(duì)照微弱,可以代入特定值作一個(gè)也許的剖析,好比當(dāng)n為16時(shí),方式的遞歸挪用歷程如下圖所示

不難看出,每次挪用時(shí),n的規(guī)模都減半,以是時(shí)間和空間復(fù)雜度都是O(logn)

若是你的算法功底還行,那就可以用更專業(yè)的方式去剖析它的復(fù)雜度(沒有一定的算法基礎(chǔ),可能會(huì)看不懂)

這實(shí)在是典型的應(yīng)用分治計(jì)謀的算法

假設(shè)T(n)是數(shù)據(jù)規(guī)模為n時(shí)的時(shí)間復(fù)雜度,不難得出遞推式:T(n) = T(n / 2) + O(1)

最后憑據(jù)遞推式 + 主定理(Master Theorem)可以直接得出結(jié)論:T(n) = O(logn)

非遞歸

我們以求3 ^ 21為例子,來剖析一下非遞歸的代碼應(yīng)該怎么寫。

首先21的二進(jìn)制形式是10101

不難得出以下結(jié)論

3 ^ n(n為2、4、8、16)都可以由3 ^ 1累乘出來

每一個(gè)3 ^ n都有對(duì)應(yīng)的二進(jìn)制位

3 ^ 1對(duì)應(yīng)二進(jìn)制位的值是1,實(shí)在是二進(jìn)制10101的最后1位

3 ^ 2對(duì)應(yīng)二進(jìn)制位的值是0,實(shí)在是二進(jìn)制1010的最后1位

3 ^ 4對(duì)應(yīng)二進(jìn)制位的值是1,實(shí)在是二進(jìn)制101的最后1位

3 ^ 8對(duì)應(yīng)二進(jìn)制位的值是0,實(shí)在是二進(jìn)制10的最后1位

3 ^ 16對(duì)應(yīng)二進(jìn)制位的值是1,實(shí)在是二進(jìn)制1的最后1位

若是3 ^ n對(duì)應(yīng)二進(jìn)制位的值是0,就不用乘進(jìn)最終效果

好比3 ^ (8 * 0)、3 ^ (2 * 0)

由于它們最終的值都是3 ^ 0,也就是1

若是3 ^ n對(duì)應(yīng)二進(jìn)制位的值是1,就需要乘進(jìn)最終效果

好比3 ^ (16 * 1)、3 ^ (4 * 1)、3 ^ (1 * 1)

以是,綜合以上種種結(jié)論,可以總結(jié)出以下解題步驟

行使3 ^ 1,不停累乘出3 ^ n(n為2、4、8、16)

每當(dāng)累乘出一個(gè)3 ^ n,就查看其對(duì)應(yīng)二進(jìn)制位的值是1照樣0,來決議是否要將它乘進(jìn)最終效果

int fastPower(int x, int n) {

int result = 1;

while (n != 0) {

if ((n & 1) == 1) {

result *= x;

}

x *= x;

n >>= 1;

}

return result;

}

代入3和21,fastPower(3, 21)的執(zhí)行流程如下

第1輪while循環(huán)

第4行代碼

n的二進(jìn)制是10101(十進(jìn)制是21)

x = 3 ^ 1, 其對(duì)應(yīng)二進(jìn)制位的值是1(n的最后一個(gè)二進(jìn)制位)

以是需要執(zhí)行第5行代碼:將x乘進(jìn)最終效果

result = 3 ^ 1

第7行代碼

x = (3 ^ 1) * (3 ^ 1) = 3 ^ 2

第8行代碼

n右移1位,其二進(jìn)制變成了1010(對(duì)應(yīng)的十進(jìn)制是啥?不重要!!!)

第2輪while循環(huán)

第4行代碼

n的二進(jìn)制是1010

x = 3 ^ 2, 其對(duì)應(yīng)二進(jìn)制位的值是0(n的最后一個(gè)二進(jìn)制位)

以是不需要執(zhí)行第5行代碼:不需要將x乘進(jìn)最終效果

result = 3 ^ 1

第7行代碼

x = (3 ^ 2) * (3 ^ 2) = 3 ^ 4

第8行代碼

n右移1位,其二進(jìn)制變成了101(對(duì)應(yīng)的十進(jìn)制是啥?不重要!!!)

第3輪while循環(huán)

第4行代碼

n的二進(jìn)制是101

x = 3 ^ 4, 其對(duì)應(yīng)二進(jìn)制位的值是1(n的最后一個(gè)二進(jìn)制位)

以是需要執(zhí)行第5行代碼:將x乘進(jìn)最終效果

result = (3 ^ 1) * (3 ^ 4)

第7行代碼

x = (3 ^ 4) * (3 ^ 4) = (3 ^ 8)

第8行代碼

n右移1位,其二進(jìn)制變成了10(對(duì)應(yīng)的十進(jìn)制是啥?不重要!!!)

第4輪while循環(huán)

第4行代碼

n的二進(jìn)制是10

x = 3 ^ 8, 其對(duì)應(yīng)二進(jìn)制位的值是0(n的最后一個(gè)二進(jìn)制位)

以是不需要執(zhí)行第5行代碼:不需要將x乘進(jìn)最終效果

result = (3 ^ 1) * (3 ^ 4)

第7行代碼

x = (3 ^ 8) * (3 ^ 8) = 3 ^ 16

第8行代碼

n右移1位,其二進(jìn)制變成了1(對(duì)應(yīng)的十進(jìn)制是啥?不重要!!!)

第5輪while循環(huán)

第4行代碼

n的二進(jìn)制是1

x = 3 ^ 16, 其對(duì)應(yīng)二進(jìn)制位的值是1(n的最后一個(gè)二進(jìn)制位)

以是需要執(zhí)行第5行代碼:將x乘進(jìn)最終效果

result = (3 ^ 1) * (3 ^ 4) * (3 ^ 16)

第7行代碼

x = (3 ^ 16) * (3 ^ 16) = 3 ^ 32

第8行代碼

n右移1位,其二進(jìn)制變成了0

最后

由于n = 0,以是退出while循環(huán)

最終result = (3 ^ 1) * (3 ^ 4) * (3 ^ 16)

復(fù)雜度剖析

每執(zhí)行一次while的循環(huán)體,n >>= 1, 會(huì)導(dǎo)致n的值減半

以是時(shí)間復(fù)雜度:O(logn)、空間復(fù)雜度:O(1)

Leetcode

Leetcode上的第50號(hào)題50. Pow(x, n),恰好就可以用今天解說的快速冪算法。以下是我的代碼實(shí)現(xiàn)

// 遞歸

public double myPow(double x, int n) {

if (n == 0) return 1;

if (n == -1) return 1 / x;

double half = myPow(x, n >> 1);

half *= half;

return ((n & 1) == 1) ? half * x : half;

}

// 非遞歸

public double myPow(double x, int n) {

long y = (n < 0) ? -((long) n) : n;

double result = 1.0;

while (y > 0) {

if ((y & 1) == 1) {

result *= x;

}

x *= x;

y >>= 1;

}

return (n < 0) ? (1 / result) : result;

}

需要提醒的是

這里我用的編程語(yǔ)言是Java,人人可以憑據(jù)自己熟悉的編程語(yǔ)言,對(duì)一些語(yǔ)法細(xì)節(jié)作出響應(yīng)的調(diào)整

Leetcode上的n可能是個(gè)負(fù)數(shù),以是上面的代碼針對(duì)負(fù)數(shù)的情形作了一些處置

更多快速冪相關(guān)的問題

時(shí)間有限,這篇文章就先說到這了哈。給小伙伴們留2個(gè)快速冪相關(guān)的問題,有空的話,可以去研究一下

使用矩陣快速冪求斐波那契數(shù)列

請(qǐng)?jiān)O(shè)計(jì)一個(gè)算法求x的y次冪模z的效果:(x ^ y) % z

假設(shè)x、y都可能是很大的整數(shù)(y大于即是0,z不即是0)

若是你稀奇希望我寫點(diǎn)什么方面的內(nèi)容,也可以留言建議,謝謝。迎接關(guān)注

原文鏈接:https://www.cnblogs.com/mjios/p/12690097.html

本站聲明:網(wǎng)站內(nèi)容來源于網(wǎng)絡(luò),若有侵權(quán),請(qǐng)聯(lián)系我們,我們將及時(shí)處置。

總結(jié)

以上是生活随笔為你收集整理的java位运算求幂,程序员必学:快速幂算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。