編程之美有一道關於階乘的題目:
1給定一個整數N,那麼N的階乘等於N!,末尾有多少個0呢,例如N=10,N!=3628800,N!的末尾有兩個0
2求N!的二進制表示中最低位爲1的位置。
階乘定義:
作者對於問題一的分析:對N!進行質因數分解: N!=2X*3Y*5Z…,因爲10=2*5,所以M與2和5的個數即X、Z有關。每一對2和5都可以得到10,故M=min(X,Z)。因爲能被2整除的數出現的頻率要比能被5整除的數出現的頻率高,所以M=Z。
解法一:
直接計算因式分解中5的指數,然後求和.
代碼實現:
#include <iostream>
using namespace std;
int findZero(int N)
{
int ret=0;
for(int i=1;i<=N;i++)
{
int j=i;
//計算每個階乘相乘數字分解因式5的個數
while(j%5==0)
{
ret++;
j/=5;
}
}
return ret;
}
解法二:
作者根據[N/k]等於1,2,3 ,…,N中能被k整除的數的個數規律,得出下面公式:
Z=[N/5]+[N/
公式中,[N/5]表示不大於N的數中5的倍數貢獻一個5,[N/
代碼實現:
#include <iostream>
using namespace std;
int findZero(int N)
{
int ret=0;
while(N)
{
//計算1,2,3...k能被當前5的指數倍數整除個數
ret+=N/5;
//累計5的指數
N/=5;
}
return ret;
}
對於問題二,確實不好想到那方面去,我們都知道在計算機二進制裏,有一個規律,那就是如果一個數是偶數,那麼該數的最後一個二進制必定是0,如果是奇數,那麼該數的最後一個二進制必定是1,這裏作者根據這樣的規律給了兩種解法。
解法一:
判斷最後一個二進制位是否爲0,若爲0,則將此二進制數右移一位,即爲商值;反之,若爲1,則說明這個二進制數是奇數,無法被2整除。
所以,這個問題實際上等同於求N!含有質因數2的個數。即答案等於N!含有質因數2的個數加1。
代碼實現:
#include <iostream>
using namespace std;
int lowestOne(int N)
{
int ret=0;
//統計被2整除的個數
while(N)
{
N>>=1;
ret+=N;
}
return ++ret;
}
解法二:
N!含有質因數2的個數,還等於N減去N的二進制表示中1的數目。我們還可以通過這個規律來求解。
下面對這個規律進行舉例說明,假設 N = 11011,那麼N!中含有質因數2的個數爲 N/2 + N/4 + N/8 + N/16 + …
即: 1101 + 110 + 11 + 1
=(1000 + 100 + 1)
+(100 + 10)
+(10 + 1)
+ 1
=(1000 + 100+ 10 + 1)+(100 + 10 + 1)+ 1
= 1111 + 111 + 1
=(10000 -1)+(1000 - 1)+(10-1)+(1-1)
= 11011-N二進制表示中1的個數
代碼實現:
#include <iostream>
using namespace std;
int lowestOne(int N)
{
int ret=0;
int temp=N;
//統計被2整除的個數
while(temp)
{
ret+=temp&1;
temp>>=1;
}
ret=N-ret;
return ++ret;
}