题目描述:
设计一个算法,计算出n阶乘中尾部零的个数
11! = 39916800,因此应该返回 2
思路:
刚开始我就想到最笨的方法,就是先把阶乘的数求出来,在不断循环进行求余操作。可是我却忽略了一点就是,计算机没用那么单位能够储存100多的阶乘之后的数目,所以此方法不同。算法如下:
算法1,时间复杂度最复杂,但是最简单的方法,只适合小数目阶乘
int top = 1;
while (n!=0) {
top*=n--;
}
long numb = 0;
while ( true ) {
int temp = top/10;
int leave = top-temp*10;
if (leave==0){
numb++;
}else{
break;
}
top/=10;
}
return numb;
之后百度找到了其他两个较好的算法,算法2的时间复杂度为O(n),算法3的时间复杂度为O(log n)
算法2:
long count = 0;
long pwr = 25;
for (long temp = 5; temp<=n;temp+=5) {
// for 循环内部的temp 是5的倍数,因此首先进行+1操作
count++;
pwr = 25;
// 判断是不是25、125、625...倍数,并根据每次Pwr的变化进行+1操作
while(temp % pwr == 0 ) {
count++;
pwr *= 5;
}
}
return count;
算法3:
思路:
这些数字是25、50、75、100、125、...=5*(5、10、15、20、25、...)=5*5*(1、2、3、4、5、...)
,内部的1、2、3、4、5、...
又满足上面的分析,因此后续的操作重复上述步骤即可。
统计一下第二次中满足条件的数字数量:n2=N/5/5
,101/25=(101/5)/5=4
。
因为25、50、75、100、125、...
它们都满足相乘后产生至少两个0,在第一次5*k
分析中已经统计过一次。对于N=101
,是20。因此此处的5*5*k
只要统计一次4即可,不需要根据25是5的二次幂统计两次。
后面的125,250,...
等乘积为1000的可以为结果贡献3个0的数字,只要在5*5*k
的基础上再统计一次n3=((N/5)/5)/5
即可。
long count = 0;
long temp = n/5;
while (temp!=0) {
count+=temp;
temp/=5;
}
return count;