欧拉计划 #36 更好的解决方案?
欧拉项目 问题 36 指出:
十进制数 585 = 1001001001(二进制)在两个基数中都是回文。
求所有小于 100 万、以 10 为底和以 2 为底的回文数的总和。
(请注意,任一基数的回文数都不能包含前导零。)
已经有一个 堆栈溢出的解决方案,但我想要一个更有效的解决方案。
例如,由于回文数不能有前导 0,因此不需要检查偶数,只需检查二进制中最后一位为 1 的奇数。这个简单的观察已经加快了“检查范围内的每个数字”的暴力破解速度。两倍。
但我想比这更聪明。理想情况下,我想要一个运行时间与总和中的数字数量成正比的算法。我认为不可能做得更好。但也许这是不可能的。例如,我们能否在与满足该属性的十进制数的数量成正比的时间内生成所有小于一百万的回文十进制数? (我认为答案是肯定的)。
解决这个回文和问题的最有效算法是什么?我想考虑由 N 参数化的运行时间:数字范围的大小(在本例中为 100 万),D:范围内的十进制回文集,B:范围内的二进制回文集。我希望运行时间为 o(N) + O( |D intersect B| ),否则,O(min(|D|, |B|))
例如二进制回文< 100:0、1、3、5、7、9、15、17、21、27、31、33、45、51、63、65、73、85、93、99
。 。 .十进制回文< 100:0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99,
两个碱基的回文:0, 1, 3 , 5, 7, 9, 33, 99
33 和 的二进制表示99 分别是 10001
和 1100011
。 下一个数字是 585 = 1001001001
,两者都是回文。
Project Euler problem 36 states:
The decimal number, 585 = 1001001001 (binary), is palindromic in both bases.
Find the sum of all numbers, less than one million, which are palindromic in base 10 and base 2.
(Please note that the palindromic number, in either base, may not include leading zeros.)
There is already a solution to this on stack overflow, but I want a more efficient solution.
For example, since the palindrome cannot have leading 0's, no even numbers need to be checked, only odd numbers for which the last bit in binary is a 1. This simple observation already speeds up the brute force "check every number in the range" by a factor of 2.
But I would like to be more clever than that. Ideally, I would like an algorithm with running time proportional to the number of numbers in the sum. I don't think it's possible to do better than that. But maybe that is not possible. Could we for example, generate all palindromic decimal numbers less than one million in time proportional to the number of decimal numbers satisfying that property? (I think the answer is yes).
What is the most efficient algorithm to solve this palindrome sum problem? I would like to consider run-times parameterized by N: the size of the range of numbers (in this case 1 million), D: the set of decimal palindromes in the range, and B: the set of binary palindromes in the range. I hope for a run-time that is o(N) + O( |D intersect B| ), or failing that, O(min(|D|, |B|))
Note: The sequences of binary and decimal palindromes are well known.
e.g. binary palindromes < 100: 0, 1, 3, 5, 7, 9, 15, 17, 21, 27, 31, 33, 45, 51, 63, 65, 73, 85, 93, 99
. . .decimal palindromes < 100:0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99,
palindromes in both bases: 0, 1, 3, 5, 7, 9, 33, 99
The binary representations of 33 and 99 are 10001
and 1100011
respectively.
The next number which is a palindrome in both is 585 = 1001001001
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
长度为
2*k
的基数b
中的回文数为(b-1)*b^(k-1)
,如下长度2*k-1
的回文数。因此,任何基数中不超过N
的回文数都是 O(sqrt(N))1。因此,如果您在一个基中生成所有回文(不超过N
),并检查它们在另一个基中是否也是回文,则您将获得 O(sqrt(N)*log(N)) 算法(对数因子来自回文检查)。这是o(N),但我还不知道它是否也是O(|D intersect B|)。这不是 O(|D intersect B|) :( 最多 1010 中只有 32 个数字在两个基数中都是回文。我没有看到任何允许仅构造这些数字的模式
。如果
N
有d
位(以b
为基数),则回文数不超过N
介于最多有d-1
位的回文数和最多有d
位的回文数(两者都包含在内)之间有(b)。 -1)*b^(k-1)
正好有k
位数字(以b
为基数),其中(b-1)*b^(floor((k-1)/2)))
是回文。求和给出最多k
位的基b
回文数,为2*(b^(k/2)-1)
(如果k
是偶数)或(b-1)*b^((k-1)/2) + 2*(b^((k-1)/2)- 1)
(如果k
是奇数)。因此,给定或取一个因子2*b
,最多包含 d 位数字的回文数为b^(d/2)
。因此,不超过N
的回文数大约为N^0.5
,其中因子以基数的倍数为界。The number of palindromes in base
b
of length2*k
is(b-1)*b^(k-1)
, as is the number of palindromes of length2*k-1
. So the number of palindromes not exceedingN
in any base is O(sqrt(N))¹. So if you generate all palindromes (not exceedingN
) in one base and check if they are also palindromes in the other base, you have an O(sqrt(N)*log(N)) algorithm (the log factor comes from the palindrome check). That's o(N), but I don't know yet if it's also O(|D intersect B|).It's not O(|D intersect B|) :( There are only 32 numbers up to 1010 which are palindromic in both bases. I don't see any pattern that would allow constructing only those.
¹ If
N
hasd
digits (in baseb
), the number of palindromes not exceedingN
is between the number of palindromes having at mostd-1
digits and the number of palindromes having at mostd
digits (both limits inclusive). There are(b-1)*b^(k-1)
numbers having exactlyk
digits (in baseb
), of which(b-1)*b^(floor((k-1)/2)))
are palindromes. Summing gives the number of base-b
palindromes with at mostk
digits as either2*(b^(k/2)-1)
(ifk
is even) or(b-1)*b^((k-1)/2) + 2*(b^((k-1)/2)-1)
(ifk
is odd). Hence, give or take a factor of2*b
, the number of palindromes with at most d digits isb^(d/2)
. Thus the number of palindromes not exceedingN
is roughlyN^0.5
, with a factor bounded by a multiple of the base considered.考虑到 1 到 1000000 之间只有大约 2000 个十进制回文。从 1 到 999,您可以将数字及其逆序串在一起,无论是否重复“中间”数字(左侧部分的最后一个数字)。对于其中的每一个,您检查它是否也是二进制回文,如果是,则它是总和的一部分。
Consider that there are only about 2000 decimal palindromes between 1 and 1000000. From 1 to 999, you can string the number and its reverse together, both with and without duplicating the "middle" digit (the last digit of the left part). For each of those, you check whether it's also a binary palindrome, and if it is, it's part of the sum.
(不是您问题的答案,而是 Project Euler 36 的一个可爱的递归位解决方案)
这可能不是最有效的算法,但我喜欢它的样子。我在阅读了 Daniel Fischer 的答案后写了这篇文章,建议在一个基数中生成所有回文,然后检查另一个基数是否也是回文。
在 18 行代码(包括括号)中,它生成所有以 2 为基数的回文,然后检查它们是否也是以 10 为基数的回文
。在我的系统上大约需要 6 毫秒。
这可能可以优化(根据我的口味,移位操作太多,这里可能有一些不必要的垃圾),并且可能有更好的算法,但我“喜欢”(+)我的代码的外观; )
(not an answer to your question but a cute recursive bit-fiddling solution to Project Euler 36)
This may not be the most efficient algorithm but I like how it looks like. I wrote it after reading Daniel Fischer's answer, suggesting to generate all palindromes in one base and then checking in the other base if it's a palindrome too.
In 18 lines of code (including the brackets) it generates all the palindromes in base 2 and then checks if they're also palindrome in base 10.
Takes about 6 ms on my system.
This can probably be optimized (too many bitshifting operation to my taste, there's probably quite some unnecessary junk here) and there may be a better algo, but I "like" (+) the look of my code ; )
我最初的假设是完全错误的,所以我已经修正了它们。我提供了两种算法,一种是迭代算法,一种是递归算法。它们显然远不如
user988052
那样令人印象深刻和高效,但它们绝对更容易阅读!第一个算法是迭代的,运行时间为 9 毫秒。第二种算法是递归的,运行时间为 16 毫秒。尽管第二种解决方案更干净,但递归调用可能会减慢速度。第一个算法(9ms):
第二个算法(16ms)
My first assumptions were entirely wrong, so I've fixed them up. I've provided two algorithms, one iterative and one recursive. They're obviously nowhere near as impressive and efficient as
user988052
's, but they're definitely easier to read! The first algorithm is iterative and has a runtime of 9ms. The second algorithm is recursive and has a runtime of 16ms. Although the second solution is cleaner, the recursive calls might be slowing it down.First Algorithm (9ms):
Second Algorithm (16ms)
这是解决这个问题的最佳 Python 实现:
Here is the best Python Implementation to solve this problem :