【演算法拾遺】階乘

蘭亭風雨發表於2014-06-04

轉載請註明出處: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的個數。這種方法的程式碼不再給出。


相關文章