不要被阶乘吓到(beauty of programe)

http://blog.csdn.net/xuelovexiao/article/details/9336047

问题一:给定一个整数N,求该整数的阶乘中末尾含有多少个0?例如:N=10;N!=3628800,N!的末尾含有两个0.

问题二:求N!的二进制表示中最低位1的位置

阶乘:是所有小于和等于该数的正整数的乘积,自然数N的阶乘是N!,这一表示法是基斯顿 卡曼引入的。阶乘定义为:一种数学计算方式。用比给定数值(必定大于等于零)小的自然数依次相乘直到最终因数为给定数值为止。记作“N!”。例如 5 的阶乘记作 5!,即 1×2×3×4×5=120。

实现一递归:

[cpp] view plain copy print ?
  1. int fun1(int num) 
  2.     if (num<0) 
  3.     { 
  4.         cout<<"error\n"
  5.     } 
  6.     else 
  7.     { 
  8.         if (num==0||num==1) 
  9.         { 
  10.             return 1; 
  11.         } 
  12.         else 
  13.         { 
  14.             return num*fun1(num-1); 
  15.         } 
  16.     } 
int fun1(int num)
{
	if (num<0)
	{
		cout<<"error\n";
	}
	else
	{
		if (num==0||num==1)
		{
			return 1;
		}
		else
		{
			return num*fun1(num-1);
		}
	}
}


实现二非递归:

[cpp] view plain copy print ?
  1. int fun2(int num) 
  2.     if (num<0) 
  3.     { 
  4.         cout<<"error\n"
  5.     } 
  6.     else 
  7.     { 
  8.         if (num==0||num==1) 
  9.         { 
  10.             return 1; 
  11.         } 
  12.         else 
  13.         { 
  14.            int sum=1; 
  15.            for (int i=1;i<=num;i++) 
  16.            { 
  17.                sum*=i; 
  18.            } 
  19.            return sum; 
  20.         } 
  21.     } 
int fun2(int num)
{
	if (num<0)
	{
		cout<<"error\n";
	}
	else
	{
		if (num==0||num==1)
		{
			return 1;
		}
		else
		{
		   int sum=1;
		   for (int i=1;i<=num;i++)
		   {
			   sum*=i;
		   }
		   return sum;
		}
	}
}



 

问题一解法

如果N!= K×10M,且K不能被10整除,那么N!末尾有M个0。再考虑对N!进行质因数分解,N!=(2^x)×(3^y)×(5^z)…,由于10 = 2×5,所以M只跟X和Z相关,每一对2和5相乘可以得到一个10,于是M = min(X, Z)。不难看出X大于等于Z,因为能被2整除的数出现的频率比能被5整除的数高得多,所以把公式简化为M = Z。

方法1:计算Z,就是计算结果里面含有5的指数,即求1到N中每个数含有的5的指数,最后求和。

[cpp] view plain copy print ?
  1. <span style="font-size: 18px;">ret = 0; 
  2. for(i = 1; i <= N; i++) 
  3.     j = i; 
  4.     while(j % 5 ==0) 
  5.     { 
  6.         ret++; 
  7.         j /= 5; 
  8.     } 
  9. }</span> 
ret = 0;
for(i = 1; i <= N; i++)
{
    j = i;
    while(j % 5 ==0)
    {
        ret++;
        j /= 5;
    }
}



 

方法2:z = [N/5] + [N/(5*5)] + [N/(5*5*5)].... */ 

/* [N/5]为N中5的个数,[N/(5*5)]为[N/5]中5的个数 */ 

/* Z为N!中含有质数5的个数 */ 

公式中,【N/5】表示不大于N的整数中5的倍数贡献一个5,[N/(5*5)] 表示不大于n的整数中25的数贡献一个5,最后求和。

[cpp] view plain copy print ?
  1. <span style="font-size: 18px;">ret = 0; 
  2. while(N) 
  3.     ret += N / 5; 
  4.     N /= 5; 
  5. }</span> 
ret = 0;
while(N)
{
    ret += N / 5;
    N /= 5;
}



 

问题二解法:

将一个数除以2,若为零说明尾部为0,右移一位;反之若为1,则说明这个二进制数是奇数,无法被2整除。所以问题二实际上等同于求N!中含有质因数2的个数,即结果右移多少位之后不能再被2整数。

[cpp] view plain copy print ?
  1. int ret = 0;   
  2.     while (n)   
  3.     {   
  4.         n >>= 1;   
  5.         ret += n;   
  6.     }   
  7.        
  8.     return ret + 1;   

 

你可能感兴趣的:(C++,c,C语言)