复试题:1000!的尾部有多少个0

以前在论坛里看过这个题,当是想:只要算下1-1000中有多少个个位数是5、0的数就可以了,坛友们也多是这么回复的,所以,我就想当然地认为自己是对的,也就没去好好地验证下这个问题

谁想,今天,我就被问到这个问题。当时想当然地说:“只要算下1-1000中有多少个个位数是2、5、0的数就可以了!”,“那你怎么转换成代码呢?”,我的内心想法大概是这样子的:“个位数是5的个数:1000 % 10 / 5 + 1000 / 10,个位数是0的个数:1000 / 10 + 1000 / 100 + 1000 / 1000",但是,我没法写出来,或者说,我深深地预感这是错的,这个式子,有种严重的“违合感”、“不对称感”,我感觉式子应该是对称的,但这里为什么处理5与0时,差之千里?一头雾水,下不了笔,本想再画画表,分析分析,但感觉,没这么容易,我想一时半会儿我是绝对想不出来的,所以,干脆地说:“嗯... 想不出来!”......

晚上回来,洗刷完毕,开始想这个问题,中午没想(因为,白天的心情被机试题,搞没了心情,唉!怎么今年总是被些简单的问题折腾的要死?),9点,开始分析这种违和感,我感觉算0的方法是对的,我就照着这个方向分析下去,花了一个多小时,终于完成,中间也用python来验证了,应该是没错的!


现在,我先来分析下100!的结果:

列举有可能得到0的数字:

5 - 10 - 15 - 20 - 25 - 30 - 35 - 40 - 45 - 50 - 55 - 60 - 65 - 70 - 75 - 80 - 85 - 90 - 100

也就说100!的尾部的0的个数

等于

(5 * 10 * 15 * 20 * 25 * 30 * 35 * 40 * 45 * 50 * 55 * 60 * 65 * 70 * 75 * 80 * 85 * 90 * 100) 的尾部的0的个数

接着,我想了很久,我想到,我可以对他们分解成 (5 * n),得到:

((5 * 1) * (5 * 2) * (5 * 3) * ... * (5 * 20)) =

pow(5, 20) * (1 * 2 * 3 * 4 * 5 * ... * 20)

而它的尾部的0的个数为:(1 * 2 * ... * 20)的尾部的0的个数 + 20,即是20!的尾部的0的个数 + 20

接着,提取5,得知它会等于

(5 * 10 * 15 * 20)的尾部的0的个数 + 20,再分解,

等于

((5 * 1) * (5 * 2) * ... * (5 * 4))的尾部的0的个数 + 20,也就是

(pow(5, 4) * (1 * 2 * 3 * 4))的尾部的0的个数 + 20

等于

(1 * 2 * 3 * 4)的结果的尾部的0的个数 + 4 + 20,

但(1 * 2 * 3 * 4)没法再提取5了,

所以,100!的尾部的0的个数就是24


总结出的方法就是:提取5的数字,分解成(5 * n),再提取,再分解...


再分析,不难发现:100!的结果就是求『1-100中,有多少个5,多少个5*5,多少个5*5*5 ......』(没明白的话,画画表,罗列罗列,应该就明白了)


得到代码:

#include <iostream>
using namespace std;

int tail_zero_count_of_factorial(int num)
{
    int count = 0;

    int base = 5;
    while (base <= num)
    {
        count += num / base;
        base *= 5;
    }

    return(count);
}

int main(int argc, char * argv[])
{
    int num[] = { 100, 994, 996, 1000, 1006 };
    
    for (int i = 0, size = sizeof(num) / sizeof(int); i < size; ++i)
    {
        cout << "tail zero count of " << num[i] << "! is "
             << tail_zero_count_of_factorial(num[i]) << endl;
    }
   
    return(0);
}

郁闷!代码,意想不到的简单!

运行结果:

tail zero count of 100! is 24
tail zero count of 994! is 245
tail zero count of 996! is 246
tail zero count of 1000! is 249
tail zero count of 1006! is 250

怕想法有漏洞,用python测试了1-1005的阶乘的情形:

right = True
for num in range(1, 1006):
	# get the factorial of num, store in value
	value = 1
	for n in range(num):
		value *= n + 1

	# get tail-zero-count of value
	count = 0
	while value > 0:
		if value % 10 == 0:
			count += 1
			value /= 10
		else:
			break

	# get tail-zero-count in my way:
	guess = 0
	base = 5
	while base <= num:
		guess += num / base
		base *= 5

	if count != guess:
		print "number: %d! -> count: %d -> guess: %d" % (num, count, guess)
		right = False
		break

if right:
	print "my way is right"

打印:my way is right


好的,应该是没问题的!


PS:面试官是女的,和我高三的英语老师同类型,和蔼可亲,爱笑,有气质



---------------------------------------- 补充 -------------------------------------------

N!中有5的个数为 count_5 = N * (1/5 + 1/25 + 1/125 + ...) --> N/4,即有:N / 5 <= count_5 < N / 4

N!中有2的个数为 count_2 = N * (1/2 + 1/4 + 1/8 + ...) --> N,即有:N / 2 <= count_2 < N

这就证明了count_5 < count_2,这就不用担心5有余而2不足了

 

### 计算机网络考研复试面试 #### OSI七层模型与TCP/IP五层模型对比 在网络体系结构方面,考生应熟悉OSI七层模型以及TCP/IP五层模型。两者的主要差异在于层次划分的不同之处[^1]。 - **OSI七层模型** - 物理层 (Physical Layer) - 数据链路层 (Data Link Layer) - 网络层 (Network Layer) - 传输层 (Transport Layer) - 会话层 (Session Layer) - 表示层 (Presentation Layer) - 应用层 (Application Layer) - **TCP/IP五层模型** - 物理层 (Physical Layer) - 数据链路层 (Data Link Layer) - 网络层 (Internet Layer) - 传输层 (Transport Layer) - 应用层 (Application Layer) 对于这两个模型的理解不仅限于记忆每一层的功能,还需要掌握不同层次间的数据封装和解封过程,了解每层的关键协议及其作用[^3]。 #### 数据在各层间的传递过程 当数据从发送方的应用程序传送到接收方时,会在各个层次之间经历一系列的操作: 1. 发送端应用程序产生的原始数据被提交给应用层; 2. 应用层附加必要的头部信息形成PDU(Protocol Data Unit),再向下一层传送; 3. 此类操作逐级重复直到物理层,期间每经过一层都会增加相应的头部或尾部用于指导后续处理; 4. 接收端则相反,自下而上剥离各级头尾直至最终交付给目标应用程序使用。 #### 关键概念解释 ##### 私有IP地址范围 为了便于内部网络管理和测试,在某些特定范围内分配了专用IPv4地址作为私网地址,这些地址不会在全球互联网中路由传播。具体如下表所示: | 类型 | 地址范围 | |------|------------------------| | A | 10.0.0.0 – 10.255.255.255 | | B | 172.16.0.0 – 172.31.255.255 | | C | 192.168.0.0 – 192.168.255.255 | ##### ARP协议工作原理 ARP(Address Resolution Protocol)负责将已知的IP地址解析成对应的MAC硬件地址。其工作机制主要包括广播查询请求包、接收到响应后更新本地缓存记录两个阶段。 ```python import socket, struct def get_mac(ip_address): try: mac = hex(struct.unpack('!L',socket.inet_aton(ip_address))[0])[2:] return ':'.join([mac[i:i+2].zfill(2).upper() for i in range(0,len(mac),2)]) except Exception as e: print(f"Error occurred while resolving IP to MAC: {e}") ``` 此代码片段仅作示意用途,并未实现真实的ARP功能。 ##### TCP三次握手与四次挥手 建立连接前双方需通过三次握手来同步序列号;断开连接时,则采用更为复杂的四步流程完成优雅关闭。这体现了TCP面向连接特性下的可靠性保障机制. #### 相关问探讨
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值