此代码需要在7000毫秒或者超时运行,我正在尝试学习ruby,所以我在这里看看是否有任何想法可以优化此代码。或者,如果您可以让我知道此代码中的哪些功能需要花费最多的时间,那么我可以专注于最有效的部分。
要解决的问题是,你必须判断任何数量的除数是奇数还是偶数。
对于n = 12,除数为[1,2,3,4,6,12] - “偶数”
对于n = 4,除数为[1,2,4] - “奇数”
非常感谢任何帮助,
感谢。
def oddity(n)
div(n) % 2 == 0 ? (return 'even'): (return 'odd')
end
def div(num)
divs = []
(1..num).each{|x| if (num % x == 0) then divs << x end}
return divs.length
end
答案 0 :(得分:1)
这里的关键观察是你只需要数量的除数,而不是除数本身。因此,一个相当简单的解决方案是将数字分解为素数,并检查我们可以形成多少组合。
require 'mathn'
def div(num)
num.prime_division.inject(1){ |prod, n| prod *= n[1] + 1 }
end
prime_division
返回一对对列表,其中第一个是素数,第二个是指数。 E.g:
12.prime_division
=> [[2, 2], [3, 1]]
我们简单地将指数相乘,每个指数加1,以说明未采用此素数的情况。
答案 1 :(得分:1)
由于性能是一个问题,让我们将OP的解决方案与@ standelaune&@ dimid&#39进行比较。
require 'prime'
require 'fruity'
n = 100_000
m = 20
tst = m.times.map { rand(n) }
#=> [30505, 26103, 53968, 24108, 78302, 99141, 22816, 67504, 10149, 28406,
# 18294, 92203, 73157, 5444, 24928, 65154, 24850, 64219, 68310, 64951]
def op(num) # Alex
divs = []
(1..num).each { |x| if (num % x == 0) then divs << x end }
divs.length
end
def test_op(tst) # Alex
tst.each { |n| op(n) }
end
def pd(num) # divid
num.prime_division.inject(1){ |prod, n| prod *= n[1] + 1 }
end
def test_pd(tst) #divid
tst.each { |n| nfacs_even?(n) }
end
def div(num) # standelaune
oddity = false
(1..num).each{|x| if (num % x == 0) then oddity = !oddity end}
oddity ? "odd" : "even"
end
def test_div(tst) # standelaune
tst.each { |n| div(n) }
end
compare do
_test_op { test_op tst }
_test_div { test_div tst }
_test_pd { test_pd tst }
end
Running each test 16 times. Test will take about 56 seconds.
_test_pd is faster than _test_div by 480x ± 100.0
_test_div is similar to _test_op
divid
方法吸引其他方法,我并不感到惊讶,因为prime_division
使用默认素数生成器Prime::Generator23(的一个实例),生成器用C编码,并且相对于Prime
子类中的其他生成器快。
答案 2 :(得分:0)
您可以通过优化算法来解决此问题。
您不必检查您正在检查的号码下面的所有数字。将您的数字分成主要组成部分就足够了。然后,组合数据的一个简单问题就是确定有多少可能的除数。
获得所有主要组件的一种方法可能是:
PRIME_SET = [2,3,5,7,11,13,17,19]
def factorize(n)
cut_off = Math.sqrt(n)
parts = []
PRIME_SET.each do |p|
return parts if p > cut_off
if n % p == 0
n = n/p
parts << p
redo
end
end
raise 'To large number for current PRIME_SET'
end
然后计算可能的数量可以通过多种不同的方式完成,并且有可能在不计算它们的情况下完成它。但这是一个天真的实现。
def count_possible_divisors(factors)
divisors = Set.new
(1..factors.length-1).each do |i|
factors.combination(i).each do |comb|
divisors.add(comb.reduce(1, :*))
end
end
divisors.length + 2 # plus 2 for 1 and n
end
这应该会比你正在做的工作少。但对于大数字来说,这是一项艰巨的任务。
答案 3 :(得分:0)
如果你想坚持你的算法,这是一个优化。
def div(num)
oddity = false
(1..num).each{|x| if (num % x == 0) then oddity = !oddity end}
oddity ? "odd" : "even"
end