我有一个任务来查找成对的友好数字,并且我已经解决了。我的解决方案效率不高,因此请帮助我加快算法的速度。
亲和数是两个不同的数,因此彼此相关,以使每个数的适当除数之和等于另一个数。最小的一对友好数字是(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}";
}
答案 0 :(得分:0)
我通常不写C#,因此,我将介绍C#-madeup-psuedo代码的一种改进,而不是偶然地遇到一些不连贯的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))
,这应该可以显着提高速度。
答案 1 :(得分:0)
有一个简单的公式可以得出一个数的除数之和,知道其素数分解:
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)
为了进行素数分解,必须计算所有素数,直到搜索范围内最大值的平方根。这可以很容易地使用Erathostenes的筛子完成。