简化这段Python代码

5

我编写了一个程序来检查我在纸上解决方案的正确性(它是正确的)。

任务:求从10到200所有数字相乘后末尾有多少个零。

答案是48,手动计算很简单。

我从未认真地用Python编写过程序,以下是我的代码:

mul = 1
for i in range(10, 200 + 1):
    mul *= i

string = str(mul)
string = string[::-1]
count = 0;
for c in str(string):
    if c == '0':
        count += 1
    else:
        break

print count
print mul

我敢打赌,在像Python这样的语言中,可以更优雅地编写相同的代码。
注:是的,这是一个作业,但不是我的 - 我只是帮了一个人 ;-)
7个回答

11

一种不涉及计算阶乘的直接实现方式,因此可以处理大数(例如2000000!)(编辑)

fives = 0
twos = 0
for i in range(10, 201):
   while i % 5 == 0:
      fives = fives + 1
      i /= 5
   while i % 2 == 0:
      twos = twos + 1
      i /= 2
print(min(fives, twos))

3
这段话的意思是:通过迭代计算阶乘的质因数分解中5和2的个数(例如10!有2个5和8个2)。由于5*2=10,且没有其他质数可以乘以10,因此质因数分解中10的个数(即末尾零的个数)是质因数分解中5的个数和2的个数的最小值。5和2的个数要比计算出来的阶乘要小很多。 - irrelephant
3
虽然问题要求10-200之间的数字,但对于更大的数字,这绝对是一种更好的方法。 对于较小的数字,实际上进行乘法运算会更快(至少在我进行 timeit 测试时是这样的)。 - snapshoe
这是一个非常有趣的方法。我喜欢它。 - Brendan Long
我检查这个只是因为它易读,而且还有很好的数学背景。 - zerkms

6
import math

answer = str(math.factorial(200) / math.factorial(9))
count = len(answer) - len(answer.rstrip('0'))
  1. 导入数学库
  2. 计算200的阶乘并减去前9个数字
  3. 去掉右侧的零并找到长度的差异

此刻最简洁 - zerkms
reduce(operator.mul, xrange(10, 200 + 1)) 不比阶乘加除法更高效吗? - Brendan Long
@Brendan Long:感谢所有回答,但我将选出最优雅的一个 ;-P - zerkms
1
当然可以 - 但我们追求的是简单性。我认为,如果您没有太多函数式编程经验,这个解决方案将是最简单的之一。 - Brian McKenna

4
print sum(1 + (not i%25) + (not i%125) for i in xrange(10,201,5))

3
import itertools
mul = reduce(lambda x,y: x*y, range(10, 200+1))
zeros = itertools.takewhile(lambda s: s == "0", reversed(str(mul)))
print len(list(zeros))

第二行计算乘积,第三行获取该数字中所有末尾零的迭代器,最后一行打印该零的数量。

2
ÕÅ»õ╗Ñþö¿operator.mulµø┐µìólambda x,y: x*yÒÇé - Ismail Badawi
xrange一起使用的range(尽管在这种情况下可能很小)。 - Brendan Long
@Brendan Long:由于我们总是从范围的开头到结尾进行迭代,所以xrange根本没有额外负担吗? - zerkms
@zerms:唯一的区别在于range会预先创建整个列表(并将其存储在内存中),而xrange只是返回数字的迭代器(它只需要存储当前数字)。在这种情况下,内存和速度的差异都可以忽略不计,但我想指出这一点,因为这是“Pythonic”的方式(在Python 3中默认)。 - Brendan Long
1
@Brendan Long:我知道它们的区别,但我一直认为xrange只适用于我们不确定是否会迭代到最后的循环。 - zerkms
@zerkms: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Usexrangeinsteadofrange 从我所了解的情况看,如果你不能使用xrange(你需要切片、需要多次迭代或其他类似问题),那么你应该只使用range。请参考https://dev59.com/N3VC5IYBdhLWcg3w9GLM - Brendan Long

3
len(re.search('0*$', str(reduce(lambda x, y: x*y, range(10, 200 + 1),1))).group(0))

1
但如果你喜欢函数式编程,这也是美丽的,因为审美观点不同! - user177800
3
我不会说这很实用。在函数式编程中,你不会看到很多正则表达式。 - Brian McKenna

2
你是说零吗?否则“null”是什么?这里是否需要一些数学知识来解决问题呢?200中有多少个5,结果是len([x for x in range(5, 201, 5)]) = 40。200中有多少个25,结果是len([x for x in range(25, 201, 5) if x%25 == 0]) = 8。200中有多少个125,结果是len([x for x in range(120, 201, 5) if x%125 == 0]) = 1。总共有49个5,因此200! = 5^49 * 2 ^49 *(其他不可被2或5整除的数字),所以有49个零。

要明确一点 - 它是48,而不是49 ;-) 我以类似的方式手动解决了它。当前的问题只是好奇如何在Python中编写“bruteforce”算法。 - zerkms
@zerkms: 我猜你一定已经做过了。我真傻! - pyfunc

0
mul = str(reduce(lambda x,y: x*y, xrange(10, 201)))
count = len(mul) - len(mul.rstrip("0"))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接