N!末尾有几个0

开年第一篇博客

我记得以前面试官问了我一个问题即:n!的末尾有几个0,当时语塞,没想起来,现在Mark一下:
Description:
对于数学阶乘N!是个很大的数,我们很难去计算,但是我们很容易计算出N!的末尾0的个数.
Input:
输入第一行包括一个整数T表示接下来的测试实例的个数,接下来的T行,每一行包括一个整数N,1<=N<=100000000
Output:
对于每一个数N,输出这个数对应末尾为0的个数
Sample Input:
3
4
60
1000
Sample Output:
0 14 249


问题分析

要求得末尾为0的个数,就要先分析一下末尾的0是怎么产生的,末尾的0肯定是由2和5产生的,一对2,5相乘产生10,这样末尾就有一个0了。按照常识,一个数中5的个数肯定是要少于2的个数,那么我们只需要求5的个数就好了。这么整个问题就变为在N!中求5的个数就行了。
如果我上面说的不够严谨,引用别人的一个解释加以理解,如下:

  1. N!=K*10^n, 其中K是不能被10整除的数,那么我们可以根据n就可以得到0的个数,那要如何思考呢
  2. 对N!进行质因数分解,即:N!=(2^x)(3^y)(5^z)…………,由于2*5=10 ,所以n只与x,z的取值相关
  3. 于是0的个数=min(x,z),我们可以判断x的个数必然大于n的个数,因为被2整除的数的频率大于被5整除的数的频率,所以n=z
  4. 你不信3的话,我给你举个例子:在100以内,能被2整除的数有:100,98,96,94,92,90 ,….,10,8,6,4,2.0。一共有51个。而能被5整除的数有:100,95,90,85,80,…,10,5,0。一共20个,嗯嗯,就是这样子的。

解法一

我们要判断的是N!中5的个数,因为N!=N*(N-1)(N-2)(N-3)……2*1
所以我们只要判断5的个数就好了,就是对N,N-1,N-2,….,10,…,2,1中的每一项进行判断,就可以的到5的个数。

代码块

以下是用Python语言实现的上述逻辑的代码:

lines=[]
count=int(input())  # 输入N的个数
for i in range(count):
    lines.append(int(input()))

def ZerosCount(N):
    """
     Count the Numner of zero in the end of the N!
    """
    num=0
    for k in range(1,N+1):
        j=k
        while(j%5==0):
              num+=1
              j=j/5
    return num
print(list(map(ZerosCount,lines)))
输出的结果为:
4
10
600
1000
10000
[2, 148, 249, 2499]

函数的partial应用
python3如何进行多行输入?

解法二

利用公式z=N/5+N/25+N/5^3+….直到N/5^k为0就好了

代码块

以下使用Python实现上述算法逻辑的代码:

lines=[]
count=int(input())
for i in range(count):
    lines.append(int(input()))
def ZerosCount(N):
    """
     Count the Numner of zero in the end of the N!
    """
    number=0
    while N:
        number+=N//5
        N=N//5
    return number
print(list(map(ZerosCount,lines)))
#输出结果如下:
4
10 
600
1000
10000
[2, 148, 249, 2499]

Process finished with exit code 0
  • 但是把代码写出来是很简单,但是其中的数学原理是什么呢,让我们一起来看一下
  • 举例1000里面5的倍数有:5,10,15,20,25,30,35,40,…,990,995,1000
    则1000里面5的个数为1000//2=200 Number=200,此时5的次数暂且为200个
  • 但是在这200个数中,有些是25的倍数,因为25=5*5,所以25要算两个5,所以5的次数要多加一次。
    1000里面25的倍数有:25,50,75,100,125,…,950,975,1000
    则1000里面25的个数为1000/25=40,所以5的次数多加40个
  • 那么接下来又因为125可以分解为5*5*5 ,即3个5,
    1000里面125的倍数有125,250,375,500,625,750,875,900。则1000里面125的个数为1000//125=8,所以5的个数多加8个
  • 那么接下来又因为625可以分解为5*5*5*5,即4个5
    1000里面625的个数为1,1000//625=1 所以5的个数多加1个
所以5的实际个数为200+40+8+1=249(个)

即,z=N/5+N/5^2+N/5^3+…,在代码里面的可以写简洁一点,归纳如下:

  number=0
    while N:
        number=numbert+N//5
        N=N//5  # 在上一个的基础上再除以5,就不用写5^n这种形式啦
    return number
#最后再看一组测试输出,感觉非常有意思
10  # 测试的个数
10
100
1000
10000
100000
1000000
10000000
100000000
1000000000
[2, 24, 249, 2499, 24999, 249998, 249998, 2499999, 24999999, 249999998]

Process finished with exit code 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值