我正在尝试为以下问题编写代码:
输入
输入以单行中的测试用例的数量t开始(t <= 10)。在下一个t行的每一行中,有两个数字m和n(1 <= m <= n <= 1000000000,n-m <= 100000)由空格分隔。
输出
对于每个测试用例,打印所有质数p,使得m <= p <= n,每行一个数,由空行分隔的测试用例。
示例输入:
2
1 10
3 5
示例输出:
2
3
5
7
3
5
我的代码:
def prime?(number)
return false if number == 1
(2..number-1).each do |n|
return false if number % n == 0
end
true
end
t = gets.strip.to_i
for i in 1..t
mi, ni = gets.strip.split(' ')
mi = mi.to_i
ni = ni.to_i
i = mi
while i <= ni
puts i if prime?(i)
i += 1
end
puts "\n"
end
代码运行正常,我遇到的唯一问题是,与其他编程语言相比,在运行大输入范围时需要花费大量时间。
我在这里做错了吗?这段代码可以进一步优化以加快运行时间吗?
我尝试过使用for循环,普通循环,创建数组然后打印它。 任何建议。
答案 0 :(得分:2)
Ruby比其他语言慢,取决于你比较它的语言;肯定比C / C ++慢。但是你的问题不是语言(尽管它会影响运行时行为),而是你找到素数的方法。有许多更好的算法可用于查找素数,例如Sieve of Eratosthenes或Sieve of Atkin。您还可以阅读维基百科上的“Generating Primes”页面,并按照其中的链接进行操作。
顺便说一下,对于Eratosthenes的筛子,甚至还有一个即用型piece of code on Stackoverflow。我相信谷歌的一些谷歌搜索也会出现其他算法的实现。
由于您的问题是在某个范围内找到素数,因此在上面的链接中找到的Sieve of Eratosthenes代码经过修改以适合您的特定问题:
def better_sieve_upto(first, last)
sieve = [nil, nil] + (2..last).to_a
sieve.each do |i|
next unless i
break if i*i > last
(i*i).step(last, i) {|j| sieve[j] = nil }
end
sieve.reject {|i| !i || i < first}
end
注意从“sieve.compact”到具有相应条件的复杂“sieve.reject”的更改。
答案 1 :(得分:0)
如果数字为2则返回true,如果数字可被2整除,则返回false。
开始迭代3,而不是2.使用两步。
迭代到数字的平方根,而不是数字减1。
def prime?(number)
return true if number == 2
return false if number <= 1 or number % 2 == 0
(3..Math.sqrt(number)).step(2) do |n|
return false if number % n == 0
end
true
end
@Technation解释说,这会更快,但仍然不会很快。
以下是使用Sieve of Eratosthenes built into Ruby的方法。您需要预先计算所有素数到最大值,这将非常快,然后选择每个范围内的素数。
require 'prime'
ranges = Array.new(gets.strip.to_i) do
min, max = gets.strip.split.map(&:to_i)
Range.new(min, max)
end
primes = Prime.each(ranges.map(&:max).max, Prime::EratosthenesGenerator.new)
ranges.each do |range|
primes.each do |prime|
next if prime < range.min
break if prime > range.max
puts prime
end
primes.rewind
puts "\n"
end
以下是各种解决方案在50000 200000范围内的表现:
正在处理的范围越多,Prime :: EratosthenesGenerator方法应该越快。