1. 程式人生 > 其它 >20的階乘是多少_階乘很簡單?恕我直言,階乘相關的面試題你還真不一定懂!...

20的階乘是多少_階乘很簡單?恕我直言,階乘相關的面試題你還真不一定懂!...

技術標籤:20的階乘是多少java階乘

來自:苦逼的碼農(微訊號:di201805)

作者:帥地

個人簡介:一個熱愛程式設計的在校生,我的世界不只有coding,還有writing。目前維護訂閱號「苦逼的碼農」,專注於寫「演算法與資料結構」,「Java」,「計算機網路」。

對於如何算 n 的階乘,只要你知道階乘的定義,我想你都知道怎麼算,但如果在面試中,面試官拋給你一道與階乘相關,看似簡單的演算法題,你還真不一定能夠給出優雅的答案!本文將分享幾道與階乘相關的案例,且難度遞增。

案例一

給定一個整數 N,那麼 N 的階乘 N! 末尾有多少個 0?例如: N = 10,則 N!= 3628800,那麼 N! 的末尾有兩個0。

有些人心想,這還不簡單,直接算出 N!的值,然後用除以 10 來判斷多少個 0 就可以了。

有些人則這樣想,直接算 N!的值再來除以 10 判斷多少個 0 的話肯定會出現溢位問題,於是開始思索:一個數乘以 10 就一定會在末尾產生一個零,於是,我們可以從“哪些數相乘能夠得到 10 ”入手。

沒錯,只有 2 * 5 才會產生 10。

注意,4 * 5 = 20 也能產生 0 啊,不過我們也可以把 20 進行分解啊,20 = 10 * 2。

於是,問題轉化為 N! 種能夠分解成多少對 2*5,再一步分析會發現,在 N!中能夠被 2 整除的數一定比能夠被 5 整除的數多,於是問題就轉化為求 1…n 這 n 個數中能夠被 5 整除的數有多少個,注意,像 25 能夠被 5整除兩次,所以25是能夠產生 2 對 2 * 5滴。有了這個思路,程式碼如下:

 1intf(intn){
2intsum=0;
3for(inti=1;i<=n;i++){
4intj=i;
5while(j%5==0){
6sum++;
7j=j/5;
8}
9}
10returnsum;
11}

有些人想出了這個規律,很是得意,然而,這還不是面試官要的答案,大家想一個問題,

當 N = 20 時,1~20 可以產生幾個 5 ?答是 4 個,此時有 N / 5 = 4。

當 N = 24 時,1~24 可以產生幾個 5 ?答是 4 個,此時有 N / 5 = 4。

當 N = 25 時,1~25 可以產生幾個 5?答是 6 個,主要是因為 25 貢獻了兩個 5,此時有 N / 5 + N / 5^2 = 6。

可以發現 產生 5 的個數為 sum = N/5 + N/5^2 + N/5^3+….

於是,最優雅的寫法應該是這樣:

1intf(intn){
2intsum=0;
3while(n!=0){
4sum+=n/5;
5n=n/5;
6}
7}

這時,你就可以自信這把程式碼扔給面試官了。

案例2

求 N! 的二進位制表示中最低位 1 的位置。例如 3!=6,二進位制為 1010,所以 最低位 1 的位置在第二位。

沒有思路?請仔細想一下這道題與上道題的關係!

仔細想一下,這道題不也是求末尾有多少個 0 嗎?你求出了末尾有多少個0自然知道 1 的位置(0的個數加1就是1的位置了),只不過,這道題是求二進位制末尾有多少個 0。

由於是二進位制,所以每次乘以 2 末尾就會產生一個 0 。

於是,模仿上面一道題,求 N!含有多少個 2 的個數。心想,幸好我做個類似了,於是一波操作猛如虎,一分鐘就寫出了程式碼:

1intf(intn){
2intsum=0;
3while(n!=0){
4sum+=n/2;
5n=n/2;
6}
7}

面試官:還能在優化嗎?

什麼鬼?還要在優化?我都 O(logn) 時間複雜度了。

還記得我之前講解了幾道有關位運算的嗎?這道題確實可以用位運算來優化,除以 n / 2 == n >> 1。不過位運算的速度快多了,於是,優化後的程式碼如下:

1intf(intn){
2intsum=0;
3while(n!=0){
4n>>=1;
5sum+=n;
6}
7}

還能在優化嗎?

可以,不過我先不講,因為我覺得,這已經夠快了。後面講其他題可能會把這道題再拿出來講。

如果你能寫出這樣的程式碼,已經算很牛逼了。

案例三

給你一個數 N,輸出 N! 的值。

沒錯,就是這麼簡單,直接讓你求階乘的值。

這個時候,你就要小心了,千萬別一波操作

1longlongsum=1;
2for(inti=1;i<=n;i++){
3sum*=i;
4
5}

一個 for 迴圈,馬上搞定。

因為你不知道 n 的範圍,有可能你用 long long 也是會溢位的,所以這個時候應該要問一下面試官有沒有限定 n 的範圍。

面試官:沒有限定!

這下好了,這道階乘的題,難度頓時上升了,說實話,我敢保證大部分人還真沒去實現過。所以,今天我就帶大家來實現一下,以防以後真的被問到。結果最熟悉的題頓時不知道怎麼下手好。

這個時候,我們就必須用字串來存放所求的值的,在相乘的時候也是用字串來相乘,說白了,就是要會求兩個大整數相乘

下面我們先來實現一個求兩個大整數相乘的函式。一種比較簡單的方法就是,像我們小學那會一樣,讓個位數與另一個數的其他數相乘,然後讓十位數與另一個的其他數相乘,最後在把他們進行相加。

d5eb0299d6e87824e8b029b81d9309b8.png

實現程式碼如下:

 1publicstaticStringmul(Strings1,Strings2){
2//先把字串轉化為字元陣列。
3char[]c1=s1.toCharArray();
4char[]c2=s2.toCharArray();
5intlen=c1.length+c2.length;
6//用來存放兩個數的積,字元的初始值為'',也就是0
7char[]c=newchar[len];
8//由於大整數的低位是在字串的末尾,所以我們從末尾遍歷來計算
9for(inti=c1.length-1;i>=0;i--){
10intindex=len-1;
11intres=0;//用來存放進位
12for(intj=c2.length-1;j>=0;j--){
13inttemp=(c1[i]-'0')*(c2[j]-'0')+c[index]+res;
14res=temp/10;
15c[index--]=(char)(temp%10);
16}
17//每趟乘下來的進位要進行儲存。
18c[index]=(char)res;
19len--;
20}
21//最後把c中的字元加上'0'
22for(inti=0;i23c[i]+='0';
24}
25Strings=newString(c);
26//n位數乘以m位數得到積位(m+n)位數或者(n+m-1)位數
27//我們只需要判斷c[0]是否為0,為0則把它捨棄。
28if(c[0]=='0')
29returns.substring(1);
30else
31returns;
32}

注意,一定要自己實現一遍,一定要自己實現一遍,因為原理簡單,但手動實現就不一定那麼簡單了,容易出現bug。

採用這種方法的話,兩個大整數相乘的時間複雜度為 O(n),其實還有更快的方法,大概時間複雜度是 O(n^1.6),不過程式碼有點小複雜,感興趣的可以閱讀這篇文章:漫畫:如何實現大整數相乘?,我這裡就不展開說了,不然單獨這個就可以另起一篇很長的文章了。

知道了兩個大整數相乘之後,我們再來算我們的階乘,就好做了,我們每次相乘的時候,只需要把它當作兩個大整數重複乘就可以了。程式碼如下:

 1//N的階乘
2publicstaticStringf(intn){
3Strings="1";
4Integert=null;
5for(inti=2;i<=n;i++){
6t=i;
7s=大整數相乘.mul(s,t.toString());
8}
9returns;
10}
11
12//大整數相乘
13publicstaticStringmul(Strings1,Strings2){
14//先把字串轉化為字元陣列。
15char[]c1=s1.toCharArray();
16char[]c2=s2.toCharArray();
17intlen=c1.length+c2.length;
18//用來存放兩個數的積,字元的初始值為'',也就是0
19char[]c=newchar[len];
20//由於大整數的低位是在字串的末尾,所以我們從末尾遍歷來計算
21for(inti=c1.length-1;i>=0;i--){
22intindex=len-1;
23intres=0;//用來存放進位
24for(intj=c2.length-1;j>=0;j--){
25inttemp=(c1[i]-'0')*(c2[j]-'0')+c[index]+res;
26res=temp/10;
27c[index--]=(char)(temp%10);
28}
29//每趟乘下來的進位要進行儲存。
30c[index]=(char)res;
31len--;
32}
33//最後把c中的字元加上'0'
34for(inti=0;i35c[i]+='0';
36}
37Strings=newString(c);
38//n位數乘以m位數得到積位(m+n)位數或者(n+m-1)位數
39//我們只需要判斷c[0]是否為0,為0則把它捨棄。
40if(c[0]=='0')
41returns.substring(1);
42else
43returns;
44}

時間複雜度是 O(n^3)。如果要優化的話,主要是在大整數相乘這裡進行優化。

總結

是不是覺得,階乘也沒有那麼簡單了?這三道與階乘相關的題,應該是比較常見的題吧,今天跟大家分享一波,希望大家有時間的話,自己也用程式碼實現一下,特別是算 N!。後面會繼續跟大家分享一些我覺得不錯的演算法題以及一些演算法技巧,敬請關注。


●編號874,輸入編號直達本文

●輸入m獲取文章目錄

推薦↓↓↓

72b61db981098faccb4b3f5de93b6736.png

程式設計師求職面試

更多推薦25個技術類公眾微信

涵蓋:程式人生、演算法與資料結構、黑客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。