一道小题目:给出一个n,求n!可被5整除多少次

先上笨方法

int GetDivideTimes(int n, int key)
{
	int result = 0;
	int sum = 1;
	for (int i = 2; i <= n; i++)
	{
		sum *= i;
	}
	while (sum % key == 0)
	{
		sum /= key;
		result++;
	}
	return result;
}

这个解法先不说效率问题,只要n稍微大一点sum值就会溢出,所以该做法不可取,我们需要换个思路。

如果定义 sum = n! = n*(n-1)!,如果n这个数不能被5整除,那么对于我们这题来说 n! 跟 (n-1)! 就完全没有区别,所以:

sum = 1*2*3*4*5*6*7*8*9*10*11*...*n

可以移除无关项后优化为:

sum = 5*10*15*...*p

这里 p 是最接近 n 的且比 n 小的5的倍数,此时右边一共多少项呢?明显是p/5项,其实也就是n/5项

这时右边的n/5项元素中的每个元素都是5的倍数,那么我们对每个元素都除一次5,一共除了n/5次,即 sum = sum / 5^(n/5),得到结果

sum = 1*2*3*4*5*...*(n/5)

结果 sum 又变成了一个阶乘即 (n/5)! ,里面又有5的倍数,我们依然可以原样优化:

sum = 5*10*15*...*q

这里 q 是最接近n/5 的且比 n/5 小的5的倍数,此时右边一共有 n/5/5 项元素

我们依然可以把右边每项元素都除以5,然后又获得新的阶乘 (n/5/5)!,这样循环下去直到这个阶乘的最大项小于5,循环结束

此时我们统计 sum 一共做了多少次除以5的操作,就表示原始 sum 可以被 5 整除多少次

把上述的过程转换为代码,真是简单到爆:

int GetDivideTimes(int n, int key)
{
	int result = 0;
	while (n >= key)
	{
		n /= key;
		result += n;
	}
	return result;
}

结束


猜你喜欢

转载自blog.csdn.net/lzdidiv/article/details/70858547