寫在前面
覺得寫得好,有所收穫,記得點個關注和點個贊,不勝感激。
我覺得吧,以後像這種純粹就是進行數學分析的問題,我就要把它記錄下來,這種問題給你時間讓你去分析,可能就能分析出來,但是限定你時間讓你解決,很容易卡住,所以遇到了就學習思路,然後以後如果碰到類似的問題,那麼解決起來就非常迅速利落了。
問題描述
問題解決
首先肯定不能依賴於把階乘算出來再去判斷有多少個零了,因爲階乘很容易就溢出了,所以先一步一步理一下思路吧。首先末尾有多少個 0
,只需要給當前數乘以一個 10
就可以加一個 0
。
再具體對於 5!
,也就是 5 * 4 * 3 * 2 * 1 = 120
,我們發現結果會有一個 0
,原因就是 2 和 5
相乘構成了一個 10
。而對於 10
的話,其實也只有 2 * 5
可以構成,所以我們只需要找有多少對 2/5
。我們把每個乘數再稍微分解下,看一個例子。
11! = 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1
=
11 * (2 * 5) * 9 * (4 * 2) * 7 * (3 * 2) * (1 * 5) * (2 * 2) * 3 * (1 * 2) * 1
對於含有 2
的因子的話是 1 * 2, 2 * 2, 3 * 2, 4 * 2 ...
。對於含有 5
的因子的話是 1 * 5, 2 * 5...
。含有 2
的因子每兩個出現一次,含有 5
的因子每 5
個出現一次,所有 2
出現的個數遠遠多於 5
,換言之找到一個 5
,一定能找到一個 2
與之配對。所以我們只需要找有多少個 5
。直接的,我們只需要判斷每個累乘的數有多少個 5
的因子即可。
public int trailingZeroes(int n) {
int count = 0;
for (int i = 1; i <= n; i++) {
int N = i;
while (N > 0) {
if (N % 5 == 0) {
count++;
N /= 5;
} else {
break;
}
}
}
return count;
}
不過上面的思路並不是最優的思路,我們還可以進一步的優化一下。對於一個數的階乘,就如之前分析的,5
的因子一定是每隔 5
個數出現一次,也就是n! = 1 * 2 * 3 * 4 * (1 * 5) * ... * (2 * 5) * ... * (3 * 5) *... * n
。因爲每隔 5
個數出現一個 5
,所以計算出現了多少個 5
,我們只需要用 n/5
就可以算出來。
但還沒有結束,繼續分析。... * (1 * 5) * ... * (1 * 5 * 5) * ... * (2 * 5 * 5) * ... * (3 * 5 * 5) * ... * n
。每隔 25
個數字,出現的是兩個 5
,所以除了每隔 5
個數算作一個 5
,每隔 25
個數,還需要多算一個 5
。也就是我們需要再加上 n / 25 個 5
。
同理我們還會發現每隔 5 * 5 * 5 = 125
個數字,會出現 3 個 5
,所以我們還需要再加上 n / 125
。綜上,規律就是每隔 5
個數,出現一個 5
,每隔 25
個數,出現 2
個 5
,每隔 125
個數,出現 3 個 5...
以此類推。最終 5
的個數就是 n / 5 + n / 25 + n / 125 ...
。寫程序的話,如果直接按照上邊的式子計算,分母可能會造成溢出。所以算 n / 25
的時候,我們先把 n
更新,n = n / 5
,然後再計算 n / 5
即可。後邊的同理。
public int trailingZeroes(int n) {
int count = 0;
while (n > 0) {
count += n / 5;
n = n / 5;
}
return count;
}