以前在论坛里看过这个题,当是想:只要算下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 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不足了