一、問題描述
給定一個正整數n,請計算n的階乘n!末尾所含有“0”的個數。例如:
- 5!=120,其末尾所含有的“0”的個數為1;
- 10!= 3628800,其末尾所含有的“0”的個數為2;
- 20!= 2432902008176640000,其末尾所含有的“0”的個數為4。
二、算法分析
此類問題很顯然屬於數學問題,一定要找到其中的本質規律才能得到正確的數學模型。
兩個大數字相乘,都可以拆分成多個質數相乘,而質數相乘結果尾數為0的,只可能是2*5。如果想到了這一點,那么就可以進一步想到:兩個數相乘尾數0的個數其實就是依賴於2和5因子的個數。又因為每兩個連續數字就會有一個因子2,個數非常充足,所以此時只需要關心5因子的個數就行了。
對於一個正整數n來說,怎么計算n!中5因子的個數呢?我們可以把5的倍數都挑出來,即:
令n! = (5*K) * (5*(K-1)) * (5*(K-2)) * ... * 5 * A,其中A就是不含5因子的數相乘結果,n = 5*K + r(0<= r <= 4)。假設f(n!)是計算階乘n!尾數0的個數,而g(n!)是計算n!中5因子的個數,那么就會有如下公式:
f(n!) = g(n!) = g(5^K * K! * A) = K + g(K!) = K + f(K!),其中K=n / 5(取整數)。
很顯然,當0 <= n <= 4時,f(n!)=0。結合這兩個公式,就搞定了這個問題了。舉幾個例子來說:
- f(5!) = 1 + f(1!) = 1
- f(10!) = 2 + f(2!) = 2
- f(20!) = 4 + f(4!) = 4
- f(100!) = 20 + f(20!) = 20 + 4 + f(4!) = 24
- f(1000!) = 200 + f(200!) = 200 + 40 + f(40!) = 240 + 8 + f(8!) = 248 + 1 + f(1) =249
三、代碼實現
使用遞歸函數來做,非常的簡單,直接套用公式即可:
#include <iostream> using namespace std; int GetN_1(int n) { if (n < 5) { return 0; } else { return (n / 5 + GetN_1(n / 5)); } } int main() { cout << GetN_1(1000) << endl; // 輸出249 system("pause"); return 0; }