Python 双底回文数,投影Euler#36

Python 双底回文数,投影Euler#36,python,Python,以下是我的解决方案,内容如下: 十进制数,585=1001₂ (二进制),在两个基中都是回文的 求以10为底和以2为底的所有回文数的总和,小于一百万 (请注意,回文数字在任何一个基中都可能不包括前导零。) 我的结果有点错误。有人能帮忙吗 def findnum(n): a = 0 for i in range(0, n + 1): temp = '{0:08b}'.format(i) if str(i) == str(i)[::-1] and st

以下是我的解决方案,内容如下:

十进制数,585=1001₂ (二进制),在两个基中都是回文的

求以10为底和以2为底的所有回文数的总和,小于一百万

(请注意,回文数字在任何一个基中都可能不包括前导零。)

我的结果有点错误。有人能帮忙吗

def findnum(n):
    a = 0
    for i in range(0, n + 1):
        temp = '{0:08b}'.format(i)
        if str(i) == str(i)[::-1] and str(temp) == str(temp)[::-1]:
            a += i 
    return a 

print findnum(1000000)

我得到的结果是872096,但正确答案似乎是872187。但这两者的区别,91,不是回文。我做错了什么?

您在问题描述中遗漏了一些内容:

请注意,回文数在任何一个基中,可能不包括前导零

但您使用的是前导零:

temp = '{0:08b}'.format(i)
从格式中删除
08
;这里根本不需要将其填充到一定的宽度:

temp = '{0:b}'.format(i)
有了这个变化,你会得到正确的答案

您也可以改用,因为您没有将字符串放入更大的模板中。您不需要将它馈送到
str()
,因为
format()
已经生成了一个字符串。我会先交换测试来测试二进制回文,避免额外的
str()
调用。
range()
调用中的
n+1
;问题描述要求所有低于100万的数字:

for i in range(n):
    temp = format(i, 'b')
    if temp == temp[::-1] and str(i) == str(i)[::-1]:
        a += i
>>> sum(1 for i in range(1000000) if str(i) == str(i)[::-1])
1999
>>> sum(1 for i in range(1000000) if format(i, 'b') == format(i, 'b')[::-1])
2000
或者,您可以先测试十进制回文,然后设置格式:

这减少了整个运行时中的许多调用,使最终版本的速度提高了一倍以上:

>>> from timeit import timeit
>>> def findnum_orig(n):
...     a = 0
...     for i in range(0, n + 1):
...         temp = '{0:b}'.format(i)
...         if str(i) == str(i)[::-1] and str(temp) == str(temp)[::-1]:
...             a += i 
...     return a 
... 
>>> def findnum_optimised(n):
...     a = 0
...     for i in range(n):
...         decimal = str(i)
...         if decimal != decimal[::-1]:
...             continue
...         binary = format(i, 'b')
...         if binary == binary[::-1]:
...             a += i
...     return a
... 
>>> timeit('fn(1000000)', 'from __main__ import findnum_orig as fn', number=10)
10.886759996414185
>>> timeit('fn(1000000)', 'from __main__ import findnum_optimised as fn', number=10)
3.7782959938049316
这是因为
str()
format()
快得多:

由于只有1999个十进制回文和2000个二进制回文低于100万:

for i in range(n):
    temp = format(i, 'b')
    if temp == temp[::-1] and str(i) == str(i)[::-1]:
        a += i
>>> sum(1 for i in range(1000000) if str(i) == str(i)[::-1])
1999
>>> sum(1 for i in range(1000000) if format(i, 'b') == format(i, 'b')[::-1])
2000
除了那些1999年的十进制回文,避免所有较慢的操作可以节省大量时间

我们可以通过切换将整数转换为二进制的方式来加快速度;也会产生一个二进制数,尽管带有
0b
前缀。即使必须使用该函数删除前缀,也比使用
format()
要快:

如果您使用的是Python2.x,还应该使用避免创建包含1.000.000个整数的列表。这将最终时间安排为:

>>> def findnum_bin_xrange(n):
...     a = 0
...     for i in xrange(n):
...         decimal = str(i)
...         if decimal != decimal[::-1]:
...             continue
...         binary = bin(i)[2:]
...         if binary == binary[::-1]:
...             a += i 
...     return a 
... 
>>> findnum_bin_xrange(1000000)
872187
>>> timeit('fn(1000000)', 'from __main__ import findnum_bin_xrange as fn', number=10)
3.5071611404418945

这大约是原始代码计时的1/3。

我的解决方案大约比Martijn快20倍

这种方法也略有不同,因为数字必须向后读取。我自己生成这些数字,而不是检查所有数字是否是回文。这将引入一些额外的代码行,因为您必须处理3种不同的情况:

  • 单个数字(1、2、3等)
  • 偶数数字(43345115等)
  • 和不均匀数字(12187378等)回文
主for循环范围可以减少到1000

首先,使用上述策略生成所有回文数(base10)。然后在base2中检查生成的数字。如果它们是回文数,则将它们添加到数组中。(如果跳过数组并在变量中求和,则速度会进一步提高。)

导入时间
#计算数字
def数字(num):
返回len(str(num))
#逆序
def反转(num):
返回int(str(num)[:-1])
#校验二进制对位符
def bin_pal_chk(编号):
b=int(箱号)[2:]
如果(b==反向(b)):
返回真值
其他:
返回错误
#包含所有以10为基数的回文的列表
佩林=[]
#计算回文
t=time.clock()
对于范围内的i(11000):
#个位数
如果(i<10):
如果本·帕尔克(i):
佩林.附加(一)
#偶数
num=i*10**位(i)+反(i)
如果bin_pal_chk(num):
palin.append(num)
#不均匀数字
如果(i<100):
对于范围(10)内的j:
num=i*10**(数字(i)+1)+j*10**数字(i)+反向(i)
如果bin_pal_chk(num):
palin.append(num)
打印时间.时钟()-t

Project Euler中的问题36是什么?你能给我们一个问题陈述吗?请在问题中添加问题的报价!在中添加到Euler#36的链接question@AnttiHaapala我看到你有14k代表,这是足够的编辑在任何信息,你觉得应该有。@Oz123:我们只是;它是一个元标记。请不要重新创建它。刚刚了解“接受我的答案”是如何工作的……社区新成员:)此外,除非数字是十进制的回文数字,否则根本不需要调用
format
。@AnttiHaapala:确实;更新以避免额外的
str()
bin()
也适用于Python3。不能发表评论也没关系。。。因为你发布了一个答案(ish)。当提到其他答案时,你应该明确哪一个,因为它们的显示顺序可能会改变。例如,“Martijn的答案”。
>>> def findnum_bin_xrange(n):
...     a = 0
...     for i in xrange(n):
...         decimal = str(i)
...         if decimal != decimal[::-1]:
...             continue
...         binary = bin(i)[2:]
...         if binary == binary[::-1]:
...             a += i 
...     return a 
... 
>>> findnum_bin_xrange(1000000)
872187
>>> timeit('fn(1000000)', 'from __main__ import findnum_bin_xrange as fn', number=10)
3.5071611404418945
import time

#calculate digits
def digits(num):
    return len(str(num))
#reverse order
def reverse(num):
  return int(str(num)[::-1])

#check binary counterpartner
def bin_pal_chk(number):
    b = int(bin(number)[2:])
    if (b == reverse(b)):
        return True
    else:
        return False

#list with all base 10 palindromes
palin = []
#calculate palindromes
t = time.clock()
for i in range(1,1000):
    #single digits
    if (i < 10):
        if bin_pal_chk(i):
            palin.append(i)
    #even digits
    num = i*10**digits(i) + reverse(i)
    if bin_pal_chk(num):
        palin.append(num)
    #uneven digits
    if (i < 100):
        for j in range(10):
            num = i*10**(digits(i)+1) + j*10**digits(i) + reverse(i)
            if bin_pal_chk(num):
                palin.append(num)
print time.clock() - t