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

58 篇文章 0 订阅
46 篇文章 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不足了

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值