Python 双底回文数,投影Euler#36
以下是我的解决方案,内容如下: 十进制数,585=1001₂ (二进制),在两个基中都是回文的 求以10为底和以2为底的所有回文数的总和,小于一百万 (请注意,回文数字在任何一个基中都可能不包括前导零。) 我的结果有点错误。有人能帮忙吗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
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等)回文李>
导入时间
#计算数字
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