Python 我能';我不知道我哪里做错了:(

Python 我能';我不知道我哪里做错了:(,python,Python,我正在用python研究euler项目的问题23。对于这个问题,我必须找到任何数字的总和,只是为了获得一些经验,你真的应该看看理解并利用内置项(与隐藏它们相比): 在dSum()(也可以简化)之外的循环可以如下所示: import itertools as it abnum = [i for i in range(1,28124) if i < dSum(i)] can = {i+j for i, j in it.product(abnum, repeat=2)} cannot = s

我正在用python研究euler项目的问题23。对于这个问题,我必须找到任何数字的总和,只是为了获得一些经验,你真的应该看看理解并利用内置项(与隐藏它们相比):

dSum()
(也可以简化)之外的循环可以如下所示:

import itertools as it

abnum = [i for i in range(1,28124) if i < dSum(i)]
can = {i+j for i, j in it.product(abnum, repeat=2)}

cannot = set(range(1,28124)) - can
print(sum(cannot)) # 4179871
按需要导入itertools
如果i
有几种方法可以改进代码

首先,这里有一个更紧凑的
dSum
版本,它与您的代码非常接近。运算符通常比函数调用快,因此我使用
**.5
而不是调用
math.sqrt
。我使用条件表达式而不是
if…else
块来计算步长。我使用内置的
求和
函数而不是
for
循环来累加除数;另外,我使用整数减法从总数中删除
n
,因为这比调用
set.remove方法更有效

def dSum(n):
    lst = set()
    for i in range(1, int(n ** .5) + 1, 2 if n % 2 else 1):
        if n % i == 0:
            lst.add(i)
            lst.add(n // i)
    return sum(lst) - n
然而,我们实际上不需要在这里使用集合。我们可以在找到除数对时添加它们,如果我们小心不要将任何除数添加两次的话

def dSum(n):
    total = 0
    for i in range(1, int(n ** .5) + 1, 2 if n % 2 else 1):
        if n % i == 0:
            j = n // i
            if i < j:
                total += i + j
            else:
                if i == j:
                    total += i
                break
    return total - n
如果我们需要为一个非常大的
num
找到除数和,一个很好的方法是找到每个数字的素幂因子,因为有一种有效的方法可以通过素幂因子分解计算除数和。然而,对于这么小的数,节省的时间不足以保证额外的代码复杂性。(如果你好奇的话,我可以添加一些素数幂筛代码;对于所有小于28124的数字,要找到除数和,素数幂筛技术的速度大约是上述代码的两倍)

AChampion的答案显示了一种非常简洁的方法,可以找到不能写成两个富足数之和的数之和。但是,它有点慢,主要是因为它在
abnum
中循环所有富足数对。这里有一种更快的方法

def main():
    num = 28124

    # Build a table of divisor sums. table[0] should be 0, but we ignore it.
    table = [1] * num
    for i in range(2, num):
        for j in range(2 * i, num, i):
            table[j] += i

    # Collect abundant numbers
    abnum = [i for i in range(2, num) if i < table[i]] 
    del table

    # Create a set for fast searching
    abset = set(abnum)
    print(len(abset), abnum[0], abnum[-1])

    total = 0
    for i in range(1, num):
        # Search for pairs of abundant numbers j <= d: j + d == i 
        for j in abnum:
            d = i - j
            if d < j:
                # No pairs were found
                total += i
                break
            if d in abset:
                break

    print(total)

if __name__ == "__main__":
    main()

这段代码在运行Python 3.6.0的旧32位单核2GHz机器上运行大约2.7秒。在Python 2上,速度大约快10%;我认为这是因为列表理解在Python 2中的开销较小(在当前范围内运行,而不是创建新范围).

这不是一个很好的问题。请尝试一下代码审查的机会,然后发布代码。@LaurentPorte因为代码现在已经发布了,但它不起作用,这是一个很好的问题,尽管不是一个很好的问题。请解释什么是Euler问题23。一个问题应该尽可能独立,谢谢@Johncolman的提示。我只是ndering是否有任何方法可以直接复制粘贴代码,而不必手动为所有行添加4个空格?当我不覆盖内置名称(如
sum
)时,当我不将集合命名为
lst
时,请删除本地未使用的变量(如
llst
),并尝试用python编写更多pythonic.Maybe查找
sum()
也能为您做些什么;-)
num = 28124

# Build a table of divisor sums.
table = [1] * num
for i in range(2, num):
    for j in range(2 * i, num, i):
        table[j] += i

# Collect abundant numbers
abnum = [i for i in range(2, num) if i < table[i]] 
print(len(abnum), abnum[0], abnum[-1])
6965 12 28122
def main():
    num = 28124

    # Build a table of divisor sums. table[0] should be 0, but we ignore it.
    table = [1] * num
    for i in range(2, num):
        for j in range(2 * i, num, i):
            table[j] += i

    # Collect abundant numbers
    abnum = [i for i in range(2, num) if i < table[i]] 
    del table

    # Create a set for fast searching
    abset = set(abnum)
    print(len(abset), abnum[0], abnum[-1])

    total = 0
    for i in range(1, num):
        # Search for pairs of abundant numbers j <= d: j + d == i 
        for j in abnum:
            d = i - j
            if d < j:
                # No pairs were found
                total += i
                break
            if d in abset:
                break

    print(total)

if __name__ == "__main__":
    main()
6965 12 28122
4179871