成对的友好数字
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了成对的友好数字相关的知识,希望对你有一定的参考价值。
我有一个任务是找到友好的数字对,我已经解决了。我的解决方案效率不高,请帮助我加快算法速度。
Amicable数字是两个不同的数字,因此相关的是每个的适当除数的总和等于另一个数。最小的一对友好数字是(220,284)。它们是友好的,因为220的适当除数是1,2,4,5,10,11,20,22,44,55和110,其中总和是284; 284的适当除数是1,2,4,71和142,其中总和是220。
任务:两个long
数字,并找到它们之间的第一个友好数字。设s(n)是n的适当除数的总和:
例如:
s(10) = 1 + 2 + 5 = 8
s(11) = 1
s(12) = 1 + 2 + 3 + 4 + 6 = 16
如果s(firstlong) == s(secondLong)
他们是友好的数字
我的代码:
public static IEnumerable<long> Ranger(long length) {
for (long i = 1; i <= length; i++) {
yield return i;
}
}
public static IEnumerable<long> GetDivisors(long num) {
return from a in Ranger(num/2)
where num % a == 0
select a;
}
public static string FindAmicable(long start, long limit) {
long numberN = 0;
long numberM = 0;
for (long n = start; n <= limit; n++) {
long sumN = GetDivisors(n).Sum();
long m = sumN;
long sumM = GetDivisors(m).Sum();
if (n == sumM ) {
numberN = n;
numberM = m;
break;
}
}
return $"First amicable numbers: {numberN} and {numberM}";
}
答案
我通常不会编写C#,所以我会描述C#-madeup-psuedo-code的改进,而不是偶然发现一些不连贯的C#意大利面。
问题似乎在你的GetDivisors
功能。这是关于每个除数O(n)
的线性n
时间,当它可能是O(sqrt(n))
。诀窍是只划分平方根,并从中推断其余因素。
GetDivisors(num) {
// same as before, but up to sqrt(num), plus a bit for floating point error
yield return a in Ranger((long)sqrt(num + 0.5)) where num % a == 0
if ((long)sqrt(num + 0.5) ** 2 == num) { // perfect square, exists
num -= 1 // don't count it twice
}
// repeat, but return the "other half"- num / a instead of a
yield return num/a in Ranger((long)sqrt(num + 0.5)) where num % a == 0
}
这将减少你从O(n)
到O(sqrt(n))
的那部分的复杂性,这应该提供明显的加速。
另一答案
有一个简单的公式给出一个知道其主要分解的数的除数之和:
let x = p1^a1 * ... * pn^an, where pi is a prime for all i
sum of divisors = (1+p1+...+p1^a1) * ... (1+pn+...+pn^an)
= (1-p1^(a1+1))/(1-p1) * ... ((1-pn^(an+1))/(1-pn)
要进行素数分解,您必须计算所有素数,直到搜索范围内最大值的平方根。使用Eratosthenes筛子很容易做到这一点。
以上是关于成对的友好数字的主要内容,如果未能解决你的问题,请参考以下文章