面試題:計算 n!階乘的結果的末尾有幾個0

前言

首先基於一個事實:咱們不可能真的把 n! 的結果計算出來,再去數結果的末尾有幾個0;n 很小還好,若是n很大,甚至趨近於無窮大,咱們是不可能這樣作的。緣由主要有二:java

  1. 通常計算機的計算能力和存儲能力也有限,是計算不出那麼大的數的。
  2. 即便計算機能算出來,這樣作也很耗時,可能要算好久。

連計算機都算不出來,那咱們怎麼辦呢?別慌,雖然咱們不能直接算出結果,但咱們能夠把問題一步步拆解。算法

拆解思路

首先,咱們想什麼狀況下會產生一個0?code

誒,一個數乘以 10,在末尾就會多出一個 0。而 10 = 5 * 2。class

一組數相乘的結果末尾有幾個0,取決於這組數因式分解後有幾對 5 和 2 的因子。效率

針對於 n! 這個題目,有這樣一個事實:把相乘的數因式分解後,2 的個數確定大於 5 的個數。循環

因此,這個問題能夠拆解爲:只要求出因式分解後有幾個 5 的因子便可,5的個數便是末尾出現的0的個數。計算機

解法一:直接法

這種解法的思路是:直接將 n! 中的每一個數,按照 5 來因式分解,最後把出現的 5 的個數加起來。時間

public int calculateZeroInFactorial(int n) {
  int count = 0;
  // 循環判斷全部的乘數
  for (int i = n; i > 0; i++) {
    if (i % 5 == 0) {
      // 若是這個乘數能夠對 5 進行因式分解,再看這個乘數能夠分解出幾個5
      int a = i;
      while(a % 5 == 0) {
        a = a / 5;
        count++;
      }
    }
  }
  return count;
}

可是這種算法的時間複雜度爲 O(nlog(n)),那有沒有更快的算法呢?while

解法二: log(n) 解法

分析:co

  1. n! 這些乘數中,每隔 5 個數,確定會有一個數至少能拆出一個 5 因子。因此 n / 5 = 至少會出現的 5 的個數。
  2. 上面說至少,由於 n / 5 並不能徹底算出 5 因子的個數,好比若某個數 25 = 5 * 5,分解後獲得的 5 也算一個,因此能被 25 因式分解至關於會出現 2 個 5 因子,而第一步中除以 5 算個數的時候已經算了一個了,因此至關於比以前會多一個 5 因子。
  3. 依此類推,能被 25 5 = 125 因式分解的至關於比以前按 25 因式分解的時候又多出一個 5 因子。能被 125 5 = 625 因式分解的至關於比按 125 因式分解時又多出一個 5 因子。還有 625 * 5 …...

因此,n! 的結果能夠拆分爲多少個 5 因子呢?

n/5 + n/25 + n /125 + n/625 + ….

好比 128!的階乘的結果末尾有幾個0呢?

128/5 +128/25 + 128/125 = 25+5+1 = 31 個

又如:1247! 的階乘的結果末尾有幾個0呢?

1247/5 + 1247/25 + 1247/125 + 1247/625 = 249+49+9+1 = 308 個

public int calculateZeroInLogN(int n) {
  int count = 0;
  while (n > 0) {
    count += n / 5;
    n /= 5;
  }
  return count;
}

這種算法的時間複雜度爲 O(log(n)),效率會高不少,並且僅需幾行代碼。

相關文章
相關標籤/搜索