【问题标题】:How to create a method that returns the nth prime number?如何创建一个返回第 n 个素数的方法?
【发布时间】:2015-02-18 06:49:19
【问题描述】:

我正在尝试编写一个返回第 n 个素数的方法。

我已经找到了解决方案,但问题出在我的方法上。我创建了大量似乎处理速度非常慢的数字。 (1..104729).to_a 确切地说。我选择 104729 是因为 n 的最大值可以是 10000,而第 10000 个整数是 104729。我正在寻找一种方法来优化我的方法。

104729 的值是否太大?有没有办法写这个,这样我就不会创建一个大数组?

方法如下:

def PrimeMover(num)

  def is_prime(x)
    i = 0
    nums = (2..x).to_a
    while nums[i] < nums.max
      if x % nums[i] != 0
        i += 1
      else
        return false
      end
    end
    return true
  end

  primes_arr = (3..104729).to_a.select {|y| is_prime(y)}

  primes_arr[num]

end

【问题讨论】:

标签: ruby primes


【解决方案1】:
require "prime"

def find_prime(nth)
  Prime.take(nth).last
end

【讨论】:

  • 这应该是选择的答案。
【解决方案2】:

结合 Ruby 的内置 prime librarylazy enumerator 以提高性能:

require 'prime'
(1...100_000).lazy.select(&:prime?).take(100).to_a

或者简单地说,正如 Arturo 强调的那样:

Prime.take(100)

【讨论】:

  • 谢谢!我并不完全了解枚举器,也没有见过lazy 或take 方法。现在会调查它。感谢您的帮助。
  • 在处理大范围时使用lazy 非常有用。将一个范围分解为一个数组会消耗大量内存并使机器瘫痪,而使用lazy 有助于避免这种情况。
【解决方案3】:

你可以使用 Ruby 的built in #prime? method,看起来很高效。

代码:

require 'prime'
primes_arr = (3..104729).to_a.select &:prime?

在我的机器上运行 2-3 秒,我觉得可以接受。

如果您需要更好的性能,或者如果您真的需要编写自己的方法,请尝试实现Sieve of Erathostenes。以下是一些 Ruby 示例:http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Ruby

【讨论】:

  • 哇。我花了很长时间才创造出这种主要方法。所以require 'prime' 调用了prime 方法?并且是select &amp;:prime? 的另一种写作方式.select{|x| x.prime?}
  • @user3640511:不,require 语句只是定义了所需的类,以便您可以使用它;标准库中有很多类在不需要它们的情况下是不可用的。是的,select(&amp;:prime?)select{|x| x.prime?} 的简写。
  • 没有。方法调用如下所示:expr.meth(args)expr.meth args 在通过评估表达式 expr 返回的对象上调用方法 meth,并将 args 作为参数传递。您可以省略接收器,在这种情况下,它暗示为self,如下所示:meth(args)meth args。因此,require 'prime' 调用 require 方法,将字符串文字 'prime' 作为参数传递。 require$LOAD_PATH 加载一个 Ruby 脚本或解释器扩展,在这种情况下,它从 Ruby 标准库加载一个文件。
【解决方案4】:

这是一个最佳is_prime 的试验划分实现,不依赖于Prime 类:

素数是只能被1和它自己整除的整数,1不是素数。所以我们想知道x 是否可以划分为小于 x 和大于 1 的任何值。所以我们从2 开始计数,并以x - 1 结束。

def prime?(x)
  return false if x < 2
  2.upto(x - 1) do |n|
    return false if (x % n).zero?
  end
  true
end

只要x % n 有余数,我们就可以打破循环并说这个数字不是素数。这样可以避免在整个范围内循环。如果用尽了所有可能的数,我们就知道这个数是素数。

这仍然不是最优的。为此,您需要sieve,或不同的检测算法来进行试验划分。但这对您的代码来说是一个很大的改进。把第 n 个交给你。

【讨论】:

  • 为这项工作点赞,但请注意 prime 不是外部库,而是默认情况下根本不加载的内置 stdlib。
  • @BorisStitnicky 啊,感谢您指出这一点。我认为它不是标准库的一部分。
  • 不错,但绝对不是最佳的。您的试除数太多了。
  • @DanaJ 是的,过去几天我一直在研究这个,现在我绝对知道是这样。最佳方案将涉及例如筛子,或其他一些不是试验设计的方案。 en.wikipedia.org/wiki/Sieve_of_Eratosthenes
  • 这是一个有趣的问题。我认为如果不限制算法(例如最佳试验划分)或输入范围,“最佳”是不可能的,即使那样也是值得怀疑的。试除法适用于非常小的输入,对 n 的平方根使用素数(或最坏的 2,然后是赔率)。在某些时候确定性 M-R 测试,然后可能是 BPSW。交叉依赖于实现和平台。非常小的输入的其他可能性是在预先筛选的位数组中查找或在小素数数组中进行二进制搜索。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-05
  • 2020-10-15
  • 2012-02-10
  • 1970-01-01
  • 1970-01-01
  • 2021-08-03
相关资源
最近更新 更多