【问题标题】:Ruby Project Euler # 12 EfficiencyRuby Project Euler # 12 效率
【发布时间】:2013-03-10 18:06:26
【问题描述】:

解决 Project Euler 的第 12 题:

三角形数的序列是通过添加自然数生成的。所以第 7 个三角形数是 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28。前十项是:

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

让我们列出前七个三角形数的因数:

1:1 3:1,3 6:1,2,3,6 10:1,2,5,10 15:1,3,5,15 21: 1,3,7,21 28:1、2、4、7、14、28

我们可以看到,28 是第一个有五个以上除数的三角形数。

第一个有五百多个除数的三角形数的值是多少?

这是我得到的:

require 'reusable'

# The idea here is that 2^n is the smallest number with n factors, 
# according to their definition, so it's a good place to start.
# It also happens to be a HUGE number, so I'm worried I'm thinking 
# about this wrong. Did 4999 instead of 5000, just to make sure 
# I didn't overshoot.
start = 2 * 4999

# The faster way to calculate the nth Triangle number
def nthTriangle(n)
 n * (n + 1) / 2
end

def answer(num)
    i = startingTriangle(num)
    while true
        triangle = i*(i+1)/2
        puts triangle
        factors = numFactors(triangle)
        return "#{triangle} is triangle number #{i}, with #{factors} factors." if factors > num
        i += 1
    end
end

# Basic reversal of the nthTriangle thing to figure
# out which n to start with in the answer function.
def startingTriangle(n)
    power = n - 2
    sqrt(power * 2).to_i - 1
end

puts answer(5000)

还有那个必需的文件(我试图将我将在一堆欧拉问题中重用的方法放入其中):

def primesUpTo(n)
  nums = [0, 0] + (2..n).to_a
  (2..sqrt(n).to_i+1).each do |i|
    if nums[i].nonzero?
      (i**2..n).step(i) {|m| nums[m] = 0}
    end
  end
  nums.find_all {|m| m.nonzero?}
end

def prime?(n)
    test = primesUpTo(sqrt(n).to_i)
    test.each do |i|
        if n % i == 0
            return false
        end
    end
    true
end

# Just for faster, more intuitive (to me) array summing
def sum(array)
    array.inject(0) {|s, n| s + n }
end

# Ditto
def product(array)
    array.inject(1) {|p, n| p * n}
end

# I don't like typing the 'Math.'
def sqrt(n)
    Math.sqrt(n)
end

# Returns an array of arrays of the prime factors of num
# Form [[factor1, power1],[factor2, power2]]
# Ex: primeFactors(12) == [[2,2],[3,1]]
def primeFactors(n)
    array = []
    # 2 3 
    primesUpTo((n/2).to_i+1).select{ |i| n % i == 0 }.each do |p|
        pcount = 1
        n = n / p
        while n % p == 0
            pcount += 1
            n = n / p
        end
        array << [p, pcount]
    end
    array
end

# Returns the number of factors a number has
# INCLUDING both the number itself and 1
# ex: numFactors(28) = 6
def numFactors(n)
    return 2 if prime?(n)
    product = 1
    primeFactors(n).each do |i|
        product *= i[1] + 1
    end
    product
end

我的问题是我的代码真的超级慢。如果我从 1 而不是我的起始编号开始,则需要一分钟 + 才能达到 200000(远不及 2^4999)。但除了废弃库素数解决方案并将所有素数添加到我一直提到的数组中——我觉得这只会让它更快一点——我想不出如何让它更快。而且它需要更快。

我认为这一切都错了吗?有什么建议吗?

关于如何提高我的任何库方法的效率的任何建议也很有用,我可能会一次又一次地使用这些方法。我想从头开始制作它们,所以我理解它们,但我担心它们的效率很低。

【问题讨论】:

  • 您的假设,即具有 n 个因子的最小数字是 2^n 显然是错误的。证明这一点是 2^5000 是深不可测的大数,事实上可观测宇宙中的原子数估计为 10^70
  • @AhmedAeonAxan 我看不出这如何算作证据。最重要的是,您没有显示 10^70 与 2^5000 的关系。
  • 我是个白痴!!!!问题是 500,而不是 5000!难怪我的程序要花很长时间。我原来的解决方案工作得很好。呃。
  • @Sasha 哦,是的,这是另一个大问题——抱歉我错过了!

标签: ruby


【解决方案1】:

来自您的代码:

这里的想法是 2^n 是具有 n 个因子的最小数

来自所述的 Project Euler 任务:

我们可以看到,28 是第一个有五个以上除数的三角形数。

我不确定你为什么认为 2^n 是 n 因子的最小数,但问题中给出的示例清楚地证明了你的假设是错误的,因为 2^5 = 32,大于 28。

我的解决方案从 1 开始搜索并且相当有效。我根本不使用素数。

附录:为了完整起见,除了从一个过高的数字开始之外,另一个大问题是搜索大于 5000 个除数而不是大于 500,正如您在厘米。

【讨论】:

  • 所以我使用素数是因为我的印象是通过素数分解找到因子的数量是最快的方法。我已经尝试过直接分解,这也需要很长时间。一个合理有效的解决方案大约需要多长时间?
  • 我的解决方案是在 Go 中,我猜在这种情况下它的运行效率会比 Ruby 高一些,在我有点旧的桌面上大约需要 850 毫秒。
  • 将我的 Go 解决方案翻译成 Ruby,在 ruby​​ 1.9.3p125 的同一台机器上需要 5.7 秒。
  • K.那么你认为一个有效编码的基本程序可以从 1 开始生成每个三角形数,并在不使用素数的情况下将它们分解,可以接近这个速度吗?还是我需要一些完全不同的东西?
  • 是的,这基本上就是我的解决方案所做的,这取决于您对 因素 的定义——我计算因素而不跟踪它们是什么。
猜你喜欢
  • 2015-05-04
  • 1970-01-01
  • 2013-12-18
  • 2023-03-21
  • 2021-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-15
相关资源
最近更新 更多