最近对将Lychrel和回文数字作为休闲数学的搜索着迷。
对于不知道的人,手动执行此检查的过程如下:
True
,否则False
。重复n
作为新的x
,直至获得True
。
有没有办法在Python中实现自动化?在哪里我可以输入一个数字,它会告诉我它的反向总和是否是回文。另外,我想知道达到这个数字需要多少步骤。
示例:
设x为79. 79 + 97为176,这不是回文,所以我们得到False
。
设x现在是176. 176 + 671是847,这不是回文,所以得到False
。
我们继续:
这是我们最终遇到回文的地方。它花了6个步骤。
答案 0 :(得分:3)
首先,定义两个便利功能(你可以自己做!):
def is_palindrome(number):
"""Whether the number is a palindrome."""
raise NotImplementedError
def reverse(number):
"""The number reversed, e.g. 79 -> 97."""
raise NotImplementedError
然后我们可以创建一个generator来生成您描述的一系列数字:
def process(number):
"""Create the required series of numbers."""
while True:
yield number
if is_palindrome(number):
break
number += reverse(number)
例如:
>>> list(process(79))
[79, 176, 847, 1595, 7546, 14003, 44044]
# 0 1 2 3 4 5 6
确定一个数字是否是一个Lychrel数字是比较棘手的 - 显然,当它不是时,我们的生成器用尽了,这是微不足道的:
def is_lychrel(number):
"""Whether the number is a Lychrel number."""
for _ in process(number):
pass
return False
你可以测试我们是否重复一个数字(如果有一个循环,它不能到达回文):
def is_lychrel(number):
"""Whether the number is a Lychrel number."""
seen = set()
for num in process(number):
if num in seen:
return True
seen.update((num, reverse(num))) # thanks @ReblochonMasque
return False
但是否则会一直持续到内存不足为止!
答案 1 :(得分:2)
关于Mathematica中链长分布的一个小实验:
f[n_] := NestWhileList[# + FromDigits@k &, n,
(# != (k = Reverse@#)) &@IntegerDigits[#] & ] // Length
(* remove known lychrel candidates *)
list = f /@ Complement[Range@1000, {196, 295, 394, 493, 592, 689, 691, 788, 790, 879,
887, 978, 986}];
Histogram@list
直到3700:
答案 2 :(得分:2)
首先,我们有一个反转数字位数的函数:
def rev(n, r=0):
if n == 0: return r
return rev(n // 10, r*10 + n%10)
然后我们可以用它来确定一个数字是否是Lychrel数;在这里,我们返回反驳该数字的Lychrel-ness的链,或单个列表以表明该数字是Lychrel:
def lychrel(n, bound=1000):
r = rev(n); chain = [n]
while bound > 0:
n += r; r = rev(n)
chain.append(n)
if n == r: return chain
bound -= 1
return [chain[0]]
以下是一些例子:
>>> lychrel(196)
[196]
>>> lychrel(281)
[281, 463, 827, 1555, 7106, 13123, 45254]
您可以在my blog了解有关Lychrel数字的更多信息。
编辑:在被Tony Suffolk 66挑战之后,我做了我向他提出的计时测试。您可以在 http://ideone.com/5gTbSH看到它们。我只使用整数的递归函数比转换为字符串并返回的函数快约30%。更快仍然是仅使用整数的函数的迭代版本。
我通常是一个Scheme程序员,而不是Python程序员,我对迭代和递归版本之间的区别感到惊讶,我将其归因于Python的函数调用开销。当我在Scheme中进行相同的实验时,迭代和递归版本之间基本上没有区别,这是有道理的,因为递归处于尾部位置,因此基本上是迭代的。
答案 3 :(得分:1)
我的代码比jonrsharpe更少Pythonic,但更接近你的例子。首先定义一个名为palindrome.py的文件:
def reverseInt(x):
"""Return the digit-reversed version of integer x (digits in decimal)."""
#Convert to string, because strings are iterable. Obtain a reverse
# iterator to the characters.
Rx = reversed(str(x))
#Obtain reversed string by joining with no intervening characters
Rx = "".join(Rx)
#Switch back to integer
Rx = int(Rx)
return Rx
def iteration(x):
"""Return a 2-tuple (n, done) where n is the result of one iteration of
the palindrome search, and done is a boolean flag indicating whether n is
a palindrome."""
Rx = reverseInt(x)
n = x + Rx
Rn = reverseInt(n)
return n, n==Rn
def depth(x):
"""Return a 2-tuple (y, numIter) where y is a palindrome and numIter
is the number of palindrome iterations needed to obtain y from x."""
numIter = 0
if x == reverseInt(x):
return x, numIter
done = False
while not done:
x, done = iteration(x)
numIter += 1
return x, numIter
现在运行python
python
>>> import palindrome as pD
>>> #pD is only for brevity, I'm being a lazy typist
>>> pD.iteration(79)
(176, False)
>>> pD.depth(79)
(44044, 6)