【算法拾遺】階乘

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章