以下是我对项目欧拉问题#12的解决方案:瓶颈在哪里?性能差距...(项目欧拉#12)
def factor this_number, number=nil, *factors
number = this_number if number.nil?
m=2
loop do
break factors << m if number % m == 0
m+=1
end
arr = factors.flatten
arr.inject(:*) != this_number ? factor(this_number, (number/factors.last), factors) : arr.uniq.collect {|k| arr.count(k)+1 }.inject(:*)
end
def highly_divisible_triangular_number number
n = 2
loop do
num = (n*(n+1)/2)
r = factor(num)
break num if (r >= number)
n+=1
end
end
puts Benchmark.measure { p highly_divisible_triangular_number(n) }
该解决方案是扎卡里丹顿的礼貌:
require 'mathn'
class Integer
def divisors
return [1] if self == 1
primes, powers = self.prime_division.transpose
exponents = powers.map{|i| (0..i).to_a}
divisors = exponents.shift.product(*exponents).map do |powers|
primes.zip(powers).map{|prime, power| prime ** power}.inject(:*)
end
divisors.sort.map{|div| [div, self/div]}
end
end
triangles = Enumerator.new do |yielder|
i = 1
loop do
yielder.yield i * (i + 1)/2
i += 1
end
end
puts Benchmark.measure { p triangles.detect { |t| t.divisors.count > n } }
基准测试结果:
__projecteuler: ruby 'problem_12a.rb' 100
73920
0.010000 0.000000 0.010000 ( 0.009514) [MINE]
73920
0.020000 0.000000 0.020000 ( 0.028339)
__projecteuler: ruby 'problem_12a.rb' 200
2031120
0.120000 0.000000 0.120000 ( 0.123996) [MINE]
2031120
0.250000 0.010000 0.260000 ( 0.251311)
__projecteuler: ruby 'problem_12a.rb' 300
2162160
0.120000 0.000000 0.120000 ( 0.122242) [MINE]
2162160
0.260000 0.000000 0.260000 ( 0.259200)
__projecteuler: ruby 'problem_12a.rb' 400
17907120
0.730000 0.000000 0.730000 ( 0.725883) [MINE]
17907120
1.050000 0.000000 1.050000 ( 1.057079)
__projecteuler: ruby 'problem_12a.rb' 500
76576500
2.650000 0.010000 2.660000 ( 2.657921) [MINE]
76576500
2.790000 0.000000 2.790000 ( 2.795859)
__projecteuler: ruby 'problem_12a.rb' 600
103672800
3.470000 0.010000 3.480000 ( 3.484551) [MINE]
103672800
3.420000 0.000000 3.420000 ( 3.419714)
__projecteuler: ruby 'problem_12a.rb' 700
236215980
7.430000 0.010000 7.440000 ( 7.438317) [MINE]
236215980
6.020000 0.020000 6.040000 ( 6.046869)
__projecteuler: ruby 'problem_12a.rb' 800
842161320
24.040000 0.020000 24.060000 (24.062911) [MINE]
842161320
14.780000 0.000000 14.780000 (14.781805)
问题
你可以从基准看到的结果我的解决方案是快了N个500
,但会随>ñ全军覆没。有人能帮我理解为什么吗?
更新 对于那些谁认为瓶颈是关系到递归,以及重试。 factor
方法,无需递归和基准不不显示改进:
__projecteuler: ruby 'problem_12a.rb' 800
842161320
24.960000 0.020000 24.980000 (24.973017) [MINE (w/o recursion)]
842161320
14.780000 0.030000 14.810000 (14.807774)
def factor this_number
number,arr=this_number,[]
done = false
until done
m=2
loop do
break arr << m if number % m == 0
m+=1
end
arr.inject(:*) != this_number ? number = number/arr.last : done = true
end
arr.uniq.collect {|k| arr.count(k)+1 }.inject(:*)
end
很好的回答。一个班轮看起来很酷,但似乎没有给出正确的答案。恕我直言,你应该使用基准测量速度,因为time.now不是一个稳定的基准测试方法。我会进一步调查你的答案。 – fyz
哦,对不起 - 单线的返回值是第i个三角数字的指数,所以解决方案是i *(i + 1)/ 2。我会添加一条评论来提及它。 – Kache
呃,有什么问题吗?看到你的un-upvote。 – Kache