寫一個算法計算n的階乘末尾0的個數

解答

首先,算出n的階乘的結果再去計算末尾有多少個0這種方法是不可取的, 由於n的階乘是一個很是大的數,分分種就會溢出。咱們應當去分析, 是什麼使n的階乘結果末尾出現0。java

n階乘末尾的0來自因子5和2相乘,5*2=10。所以,咱們只須要計算n的階乘裏, 有多少對5和2。注意到2出現的頻率比5多,所以,咱們只須要計算有多少個因子5便可。 咱們能夠列舉一些例子,看看須要注意些什麼:算法

 

5!, 包含1*5, 1個5 10!, 包含1*5,2*5, 2個5 15!, 包含1*5,2*5,3*5, 3個5 20!, 包含1*5,2*5,3*5,4*5, 4個5 25!, 包含1*5,2*5,3*5,4*5,5*5, 6個5 ...app

1spa

2.net

3code

4blog

5ip

6ci

7get

5!, 包含1*5, 1個5

10!, 包含1*5,2*5, 2個5

15!, 包含1*5,2*5,3*5, 3個5

20!, 包含1*5,2*5,3*5,4*5, 4個5

25!, 包含1*5,2*5,3*5,4*5,5*5, 6個5

...

 

 

給定一個n,用n除以5,獲得的是從1到n中包含1個5的數的個數;而後用n除以5去更新n, 至關於把每個包含5的數中的因子5取出來一個。而後繼續一樣的操做,讓n除以5, 將獲得此時仍包含有5的數的個數,依次類推。最後把計算出來的個數相加便可。 好比計算25的階乘中末尾有幾個0, 先用25除以5獲得5,表示咱們從5,10,15,20,25中各拿一個因子5出來,總共拿了5個。 更新n=25/5=5,再用n除以5獲得1,表示咱們從25中拿出另外一個因子5, 其它的在第一次除以5後就再也不包含因子5了。

代碼以下:

 

int NumZeros(int n){ if(n < 0) return -1; int num = 0; while((n /= 5) > 0){ num += n; } return num; }

1

2

3

4

5

6

7

8

int NumZeros(int n){

    if(n < 0) return -1;

    int num = 0;

    while((n /= 5) > 0){

        num += n;

    }

    return num;

}

 

思路一:

    計算出n!= nValue,而後 nValue % 10 == 0 則nCount自增1,nValue /= 10 直到條件爲否,最後nCount就是咱們想要的結果,代碼以下:

C\C++

int CountZero(int n)
{
    unsign long long nValue = 1;
    for (int i = 2; i <= n; i ++)
    {
        nValue *=i;
    }
    int nCount = 0;
    while(0 == nValue % 10)
    {
        nCount ++;
        nValue /= 10;        
    }
    return nCount;
}

 

    代碼簡潔易懂,看上去還不賴,可是這裏要考慮一個問題就是在求n!整數溢出了怎麼辦?  顯然咱們使用_int64也一樣會有溢出的時候,因此上面的代碼其實是不可行的。

 

思路二:

    不知道怎麼辦,不妨先舉例分析:

1! = 1
2! = 1 * 2 = 2
3! = 1 * 2 *3 = 6
4! = 1 * 2 * 3 * 4 = 24
5! = 1 * 2 * 3 * 4 * 5 = 120
........
1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13
* 14 * 15 * 16 * 17 * 18 * 19 * 20 * 21 * 22 *23 * 24 * 25

 

咱們會發現一個因子2和因子5組合產生一個0,這樣咱們只需統計1到n有多少個因子對,即n!的尾隨零個數,因子2的個數比因子5的個數多,所以咱們只需統計出因子5的個數便可,如

5,10,15,25,30,35,40.......

 

須要注意的是,以100!爲例:

統計一次5的倍數 (5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100)= 20

統計一次25的倍數(由於25的倍數有兩個5的因子,因此再統計一次)(25,50,75,100) = 4

統計一次125的倍數(125的倍數由3個5的因子,因此再統計一次,以此類推)(nil)

因此100!的尾隨零個數爲24個

實現代碼以下:

C\C++

int CountZero(int n)
{
    int count = 0;
    if (n < 0)
        return -1;
    for (int i = 5; n / i > 0; i *= 5)
        count += n / i;
    return count;
}

運行結果:

1 1 0 0
2 2 0 0
3 6 0 0
4 24 0 0
5 120 1 1
6 720 1 1
7 5040 1 1
8 40320 1 1
9 362880 1 1
10 3628800 2 2
11 39916800 2 2
12 479001600 2 2
13 6227020800 2 2
14 87178291200 2 2
15 1307674368000 3 3
16 20922789888000 3 3
17 355687428096000 3 3
18 6402373705728000 3 3
19 121645100408832000 3 3
20 2432902008176640000 4 4
21 14197454024290336768 0 4
22 17196083355034583040 1 4
23 8128291617894825984 0 4
24 10611558092380307456 0 4

 

 當n=21時,21!已經溢出。Done!

分析:

就是算,階乘中總共有幾個 2*5,又由於2老是比5多,因此算出有幾個5相乘就能夠。

注意:25算兩個,由於5*5, 125算三個,由於5*5*5.

具體算法是這樣,

第一遍,算階乘中5的倍數有幾個,即 n/5

第二遍,算階乘中25的倍數有幾個,即n/25,(這裏25就不用算兩次,由於在算5的倍數時已經算了一次25)

。。。。。。

最後將這些結果相加即爲所求。

 

[java] view plain copy

在CODE上查看代碼片派生到個人代碼片

  1. package cci.section17;  
  2.   
  3. public class CCI_17_3 {  
  4.       
  5.     public static int zeroNum(int n){  
  6.         int num = 0;  
  7.         if(n<0) return -1;  
  8.         for(int i=5; n/i>0; i*=5){  
  9.             num += n/i;  
  10.         }  
  11.         return num;  
  12.     }  
  13.   
  14.     public static void main(String[] args) {  
  15.         // TODO Auto-generated method stub  
  16.         System.out.println(zeroNum(30));//6  
  17.     }  
  18.   
相關文章
相關標籤/搜索