早上好
我编写了以下代码,该代码适用于小数数字,以找到数字的最大质数。我不能使用Prime
,我需要提出一个手动解决方案。
def is_prime?(number)
list = (2..(Math.sqrt(number))).to_a
list.each do |i|
return false if number % i == 0
end
true
end
def biggest_prime(number)
list = (2..((number))).to_a
divisors = list.select{|i| is_prime?(i)}
divisors.select{|i| number % i == 0 }.max
end
13195的主要因子是5、7、13和29。
biggest_prime(13195) => 29
但是,当我尝试使用biggest_prime(600851475143)
的边缘情况时,系统将冻结。
任何人都可以告诉我如何重构代码以使其更有效率吗?
非常感谢!
答案 0 :(得分:8)
您的代码有很多问题,使其效率大大降低:
biggest_prime
方法中,您将在每个小于目标数字的数字中构造一个Array
,而不仅仅是遍历该范围。对于600851475143
,该Array
在内存中的大小约为4 TiByte。您有4 TiByte的RAM吗?如果没有,您的系统将创建一个巨大的交换文件并不断交换。请改用Range
!实际上,您已经已经使用Range
,但是完全没有理由将其转换为Array
。is_prime?
方法中也会发生同样的情况。这个Array
小得多(最大时只有大约6 MiByte),但是您一次又一次地创建它,次数达600次十亿!创建n个数字的Array
需要O(n)的时间,因此,创建n次Array
的sqrt(n)数字需要的O(n * sqrt(n))时间。总共需要SUM(sqrt(n),n = 1到600851475143)步,大约是310498000000000000步。因此,您需要做的是大量减少迭代次数和内存量。
后者最简单:使用Range
而不是Array
。
前者需要一些思考。这是一个主意:您一次又一次检查相同的数字。没必要一旦确定数字是除数,就已经知道它是除数,您无需再次检查。
同样,您一次又一次地检查相同的数字的素性。但是,一旦确定数字是质数,就不需要再次检查,毕竟改变的可能性很小。
但是首先,让我们看一下最有效解决方案的外观:
require 'prime'
def biggest_prime(number)
number.prime_division.last.first
end
答案 1 :(得分:3)
我个人将只使用内置功能,而不是尝试重新发明轮子。
require 'prime'
number = 13195
Prime.each(number).select { |n| number % n == 0 }
这将导致[5, 7, 13, 29]
的预期输出。
最后一个值将始终是最大值,所以...
Prime.each(number).select { |n| number % n == 0 }.last
给出您要寻找的29
。显然可以将其清除一点,但可以给您一个提示。
这将以完全相同的数字“冻结”,这很可能会进入Bignum
并超出32位整数范围(对于Ruby实际上为31位)。不过,我将不得不深入研究C代码以了解冻结的含义,或者使用其他一些64位及更高的数字进行测试以查看结果是否可重复。
答案 2 :(得分:1)
当我们看到论文中应该解决的问题时,我们可以使用prime_division。它为您提供一组您的数字除以的素数对。它可以快速处理大数字。
// 'targetMessage' contains the message ID
// 'targetReaction' contains the reaction to be added
// 'role' contains the ID of the role, the user should receive
// 'mongo()' simply connects to the database
await mongo().then(async mongoose => {
try {
await messageReactionSchema.findOneAndUpdate({
_id: guild.id,
message: {
$elemMatch: {
msgId: targetMessage,
},
},
}, {
_id: guild.id,
$push: {
message: [{
msgId: targetMessage,
reactionRole: [{
reaction: targetReaction,
role,
}],
}],
},
}, {
upsert: true,
});
}
finally {
mongoose.connection.close();
}
});
答案 3 :(得分:0)
您可以通过更改除以的最大数来进行操作,直到没有更多的质数可用于划分。这样,您就不必在乎中间质数,而可以大大减少迭代次数:)
def top_prime(n)
max = n
lower = 2
while lower < max
while max % lower == 0 && max != lower
max = max / lower
end
lower = lower+1
end
max
end
puts top_prime(600851475143)