成对的友好数字

问题描述 投票:0回答:2

我有一个任务是找到友好的数字对,我已经解决了。我的解决方案效率不高,请帮助我加快算法速度。

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# algorithm math
2个回答
0
投票

我通常不会编写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))的那部分的复杂性,这应该提供明显的加速。


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)

要进行素数分解,您必须计算所有素数,直到搜索范围内最大值的平方根。使用Eratosthenes筛子很容易做到这一点。

© www.soinside.com 2019 - 2024. All rights reserved.