轉載請註明出處:http://blog.csdn.net/ns_code/article/details/28335353
前言
主要看兩道有關階乘的題目,從中可以看出一些規律來。
題目一
N!末尾0的個數
找末尾0出現的個數,那我們就要找產生0的乘數,即哪些數相乘會得到10。我們需要對N!進行質因數分解,由於10 = 2*5,因此0的個數至於N!中2和5出現的的對數有關,而能被2整除的數出現的頻率比能被5整除的數要多得多,因此我們找出N!中質因數5出現的個數,即爲N!末尾0的個數。
方法一
最直接的方法,就是計算1-N中每個數的因式分解中5的個數,然後相加,代碼如下:
int FactorialNum0_1(int n)
{
int count = 0;
int i;
for(i=1;i<=n;i++)
{
int j = i;
while(j%5 == 0)
{
count++;
j /= 5;
}
}
return count;
}
這種方法的時間複雜度爲O(n)。方法二
方法一中對不含質因數5的數也進行了判斷,時間複雜度較高。
第二種方法要用到如下結論:
N!中含有的質因數k的個數爲:[N/k]+[N/k^2]+[N/k^3]+...(總會存在一個t,使得k^t>N,便有[N/k^t]=0)
這個公式的證明並不難,自己嘗試去理解下,其中[N/k]等於1,2,3...N中能被k整除的數的個數。
用該方法寫成的代碼如下;
int FactorialNum0_2(int n)
{
int count = 0;
while(n)
{
count += n/5;
n /= 5;
}
return count;
}
該方法的時間複雜度爲O(log5n)(這裏是以5爲底n的對數)。題目二
N!二進制表示中最低位1的位置
比如3!爲6,二進制爲1010,那麼最低位的1的位置爲2,這裏最左邊的位置從1開始計算。
方法一
我們假設最低位的1的位置爲第k位,則N!=2^(k-1)+...+2^t+...+2^p+...,這裏t,p等意味着後面的第t+1位,第p+1位也爲1,且p>t>k。這樣很容易看出來,N!中質因數2的個數爲k-1個,也就是說,最低位1的位置即爲N!中質因數2的個數加1,因此問題又轉化爲了求N!中質因數2的個數了,同樣利用結論:
N!中含有的質因數k的個數爲:[N/k]+[N/k^2]+[N/k^3]+...(總會存在一個t,使得k^t>N,便有[N/k^t]=0)
這樣寫出的代碼如下:
int Lowest1(int n)
{
int count = 0;
while(n)
{
count += n/2;
n /= 2;
}
return count + 1;
}
該方法時間複雜度爲O(log2n)(這裏是以2爲底n的對數)。方法二
用如下結論:N!中含有質因數2的個數,等於N減去N的二進制表示中1的個數,關於如何求N的二進制表示中1的個數,參考我的這篇博文;http://blog.csdn.net/ns_code/article/details/25425577,最快的方法的操作步驟只與二進制中1的個數相等,因此這種方法的時間複雜度更好一些,雖然方法一已經很快了,這種方法的時間複雜度爲O(k),其中k爲N!中1的個數。這種方法的代碼不再給出。