我为Project Euler - Problem 36编写了以下方法。所有这一切都是将基数10和基数2中所有小于1,000,000的数字加起来。
def problem_36
(1...1_000_000).select do |n|
n.to_s == n.to_s.reverse && n.to_s(2) == n.to_s(2).reverse
end
end
现在,这可以工作,并在1秒钟内给出正确的结果。我希望在1秒内得到它,所以我决定减少将数字转换为字符串的次数。所以我做了以下更改:
def problem_36
(1...1_000_000).select do |n|
base10 = n.to_s
base2 = n.to_s(2)
base10 == base10.reverse && base2 == base2.reverse
end
end
问题是,这个版本实际上比原来的版本运行了大约50%慢。所以问题是:分配这两个变量真的很慢吗?或者Ruby是否优化链式方法调用?
答案 0 :(得分:7)
在这一行
n.to_s == n.to_s.reverse && n.to_s(2) == n.to_s(2).reverse
如果第一部分是false
(Ruby的&&
运算符短路,unlike its &
counterpart),则不执行第二部分。这节省了很多对to_s(2)
的调用。
答案 1 :(得分:0)
有趣。
通常的Ruby性能规则是,如果程序使用内置操作,它将会很快。如果没有,那就会很慢。
即使您的第二个版本可能会或可能不会执行更少的转换,但它会执行三个Ruby行与一个。
我曾经读过一个大型日志文件。在我的第一个版本中,我使用Ruby代码保留了一个有效的行链表。
1。时间复杂度:O(1)。
然后我将其更改为仅使用<<
并将每个新节点添加到数组的末尾。
2. 时间复杂度:O(N 2 ),或至少为O(N 1 +ε)
第二个版本(1)更快。
1。显然,实现是将数组扩展为块,因此它不是完全二次的,但仍然比链表更多的工作。