繁体   English   中英

使用 python 的 Euler 项目 #5

[英]Project Euler #5 using python

问题陈述是这样的:

2520 是可以被 1 到 10 中的每个数字整除而没有任何余数的最小数字。

能被 1 到 20 的所有数整除的最小正数是多少?

这是我的解决方案:

x=2520.0
list=[]
true_list=[11.0, 12.0, 13.0, 14.0, 16.0, 17.0, 18.0, 19.0, 20.0]
b=1
def test():
    for n in true_list:
        z=x/n
        if z%2==0:
            list.append(n)
while b==1:
    test()
    if list==true_list:
        b=2
        print x
    else:
        x=x+20
        list=[]

-> 基本上,我定义了一个由函数 test() 填充的空列表。 test() 的作用是检查给定的数字(在本例中为 x)是否可以被 11-20 的值整除。 如果是,则将该值(介于 11-20 之间)放入空列表中。

当 test() 运行时,程序会检查列表是否等于包含 11-20 的所有数字的预定义 true_list。 如果是,则打印 x。 否则,程序在增加 x 的值后继续。

这意味着如果 list 等于 true_list,则 11-20 中的所有数字均等除我们的数字 (x),这就是问题中的要求。

运行一分钟左右后,它给出了答案:465585120.0。 这恰好是不正确的。 我不知道这是为什么。 我已经尝试解决这个问题超过 8 个小时了,但我的智慧已告一段落。 错误是什么?

您不需要提前阅读,但如果您对我在解决方案中使用某些东西的原因有疑问,那么我在这里解决了其中的一些问题:

->我没有使用 true_list 中的所有 20 个数字来加速程序,因为任何可以被 11-20 整除的数字也可以被 1-20 整除。

->我使用 x=x+20 来加速程序,因为它与 x=x+1 或 x+2 一样有效;只是,它更快。

->我使用了浮点值,因为我在函数“test()”中使用了 z=x/n,我不想去掉小数部分,因为这样做会使浮点值也适合后续操作,即z%2。

例子:

1) 使用 int 值:

x=17
n=2
z=x/n=8

在这里, z%2==0 是有效的,这不应该是这种情况,因为它实际上在数学中无效。

2) 带有浮点值:

x=17.0
n=2.0
z=x/n=8.5

在这里, z%n != 0应该是这样。

就像其他人提到的那样,只需找到 lcm,但这里有一个简单的方法。 只要记住 lcm(a, b, c) = lcm(a, lcm(b, c))。 这就是全部:

from fractions import gcd

print(reduce(lambda a, b: a * b / gcd(a, b), range(1, 21)))

如果您想编写自己的 gcd 函数,它的工作方式如下( https://en.wikipedia.org/wiki/Euclidean_algorithm ):

def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

首先,正如我在评论中所说的,你为什么要尝试以蛮力的方式来做呢? 您可以在几秒钟内更轻松地计算数字 1 到 20 的 LCM。

其次,你的代码行,

if z%2==0:
        list.append(n)

这基本上给了你你想要的答案的两倍,因为这个语句会导致你计算 LCM*2,因为它必须除以额外的因子 2。

正确答案是 232792560,这是我用一张纸和计算器在 <20 秒内计算出来的。 如您所见,您得到的答案是两倍

<-- 编辑我之前的代码是错误的。 这个有效----->

您可以通过执行以下操作来纠正此问题:

x=2520.0
list=[]
true_list=[11.0, 12.0, 13.0, 14.0, 16.0, 17.0, 18.0, 19.0, 20.0]
b=1
def test():
     for n in true_list:
        if x%n==0:
            list.append(n)
while b==1:
    test()
    if list==true_list:
        b=2
        print(x)
    else:
        x=x+20
        list=[]

这是通过计算 LCM 来实现的方法:

allFactors={}
#for each divisor (ignore 1 as it can divide into everything)
for n in range(2,21,1):
    factors={}
    i=2
    while i<=n:
        while n%i==0:
            try:
                factors[i]+=1
            except KeyError:
                factors[i]=1
            n=n/i
        i+=1

    for pf,v in factors.iteritems():
        try:
            if allFactors[pf] < v:
                allFactors[pf]=v
        except KeyError:
            allFactors[pf]=v
lcm=1
for pf,v in allFactors.iteritems():
    lcm=lcm*(int(pf)**v)

print(lcm)

%运算符称为“模数”运算符。 英语: a % b读作“a mod b”,意思是“ a/b的余数”。 所以100%3=112%5=2

检查整除性的一种常见方法是检查“我的数字是否以我的除数为模等于 0?”。 或者在代码中:

if a%b == 0:
    print("b divides a!")

在您的代码中,您要检查n除以x 你检查过:

z=x/n
if z%2==0:
    print("n divides x?") #No not really

zxn的商。 if z%2==0可以解释为“如果 z 可以被 2 整除”。 所以你问“x 和 n 的商能被 2 整除吗?” 这当然远不及你想要的。 而是简单地做

if x%n==0:
    print("n divides x?") # YES!

我建议你做几个 python 教程,这样你就可以在尝试问题之前掌握基础知识。 :)

如果您需要更多帮助,请告诉我。 :)

有很多方法可以解决这个问题。 由于您正在进行 Project Euler 的早期练习,我想您想开发一种方法来帮助您理解基本的 Python 构造(与gcd等的“包含电池”方法相反)。

这是一种基本方法,在运行时或开发人员时效率不高 :) 但一个不错的练习:

found = None
n = 0

while not found:
    n += 1
    for d in xrange(2,21):
        if n % d:
            break
    else:
        found = n

print found

是这样的:

  • 检查从 0 开始的分子n 。(您实际上可以从 2520 开始,因为我们知道答案必须不小于 1-10 情况的答案,但这是一个微小的优化。)

  • 永远循环直到找到解决方案。 (在现实世界的程序中,您可能会进行某种安全检查,因此它不能永远运行,但这对于我们正在做的事情来说很好。)

  • 如果我们还没有找到解决方案,那么将下一轮的分子加一。

  • 将分子除以 2-20 范围内的分母d 如果d任何值导致非零余数,则跳出循环 - 测试剩余的分母毫无意义。 (如果我们想提高效率,我们可以使用xrange(2,n)因为除以大于分子的值没有意义。如果效率是一个极端的问题,比如如果范围大得多(2- 1000 而不是 2-20),我们实际上可以使用xrange(2,floor(sqrt(n))因为对于大于平方根的除数,不可能没有余数)。

  • 如果我们在没有提前中断的情况下一直通过for循环, else子句就会运行,我们会记录分子的当前值 - 这就是解决方案。

这种方法显然是蛮力。 作为学习练习很好。 对于同一问题的更大版本,您最好使用 Euclid 算法和硬件感知优化。

import time
start_time = time.time()

for i in range(2520,10000000000):
    if i % 11 == 0 and\
    i % 12 == 0 and\
    i % 13 == 0 and\
    i % 14 == 0 and\
    i % 15 == 0 and\
    i % 16 == 0 and\
    i % 17 == 0 and\
    i % 18 == 0 and\
    i % 19 == 0 and\
    i % 20 == 0:
        print(i)
        break

print(time.time() - start_time," seconds")

你可以分别找到质数和合数的 LCM,然后找到它们的 LCM 的 LCM。 在几乎一秒钟内完成工作! 这是我的代码:

import time

start_time = time.time()
nums = []
primeNums = []
allNums = []

def findFactors(num):
    factors = []
    for i in range(1, num + 1):
        if num % i == 0:
            if i not in factors:
                factors.append(i)
                x = int(num / i)
                factors.append(x)
            else:
                break
    return factors
 

def isDivisibleByAll(number, numbers):
    isDivisbleBy = []
    for num in numbers:
        if number % num == 0:
            isDivisbleBy.append(num)
    return isDivisbleBy == numbers



for i in range(11, 21):
    nums.append(i)

for num in nums:
    if findFactors(num) == [1, num]:
        primeNums.append(num)
        nums.remove(num)

currentNum = nums[-1]
currentPrimeNum = primeNums[-1]
while isDivisibleByAll(currentNum, nums) == False:
    currentNum = currentNum + nums[-1]
    print(currentNum)

while isDivisibleByAll(currentPrimeNum, primeNums) == False:
    currentPrimeNum = currentPrimeNum + primeNums[-1]
    print(currentPrimeNum)

allNums.append(currentNum)
allNums.append(currentPrimeNum)
currentAllNum = allNums[-1]

while isDivisibleByAll(currentAllNum, nums) == False:
    currentAllNum = currentAllNum + allNums[-1]
    print(currentAllNum)

print(currentNum, currentPrimeNum, currentAllNum)
end_time = time.time()

print("Time taken: ", end_time - start_time)

解决此问题的更有效和更短的方法将是下面提到的代码。 所以,正如我们从问题中知道的,能被 1 到 10 之间的所有数整除的数是 2520。我们知道x的因数也是yx的因数。 所以,我们可以创建一个函数来检查这个数字是否可以被从 11 到 20 的所有数字整除。我们可以创建一个 while 循环,其中将x的值增加2520直到 x 的值是答案。

 def isdivisiblebyall(n): for i in range(11, 21): if n % i != 0: return False return True no = 2520 while not isdivisiblebyall(no): ## if number is not divisible by range of 11 to 20 the value of 'no' will be incremented by 2520 no+=2520 print(no)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM