【问题标题】:Pairs of amicable numbers友好的数字对
【发布时间】:2019-03-14 08:15:26
【问题描述】:

我的任务是找到一对友好的数字,我已经解决了。我的解决方案效率不高,所以请帮我让我的算法更快。

友好的数字是两个不同的数字,它们之间的关系使得每个数字的真除数之和等于另一个数字。最小的友好数对是 (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}";
}

【问题讨论】:

  • 第一个帮助,不是很多,我可以说你的范围函数可以从 2 开始,因为所有数字都可以被 1 整除,那么你不必检查和求和这个。我会检查选项,因为我认为关键是检查数字的除数,从某一刻开始,然后你就知道它是否适合或中断到下一个。
  • 帮助不大,但根据维基百科,不存在奇偶偶数对(它可能存在但仍未找到)所以如果 n 是奇数/偶数并且 sumN=偶数/奇数你可以拒绝。此外,Vaxasoftware 有一个庞大的 maicable 号码列表,可能对您有所帮助。
  • 看看你能不能从这个问题中得到什么stackoverflow.com/questions/41653159/…
  • 您还可以记住给定 n 的总和,尽管这只会在多个 ns 生成相同 m 的情况下有所帮助,我不知道这是否会在实践中发生。我也不清楚 m 是否也需要在 start 和 limit 之间,你没有检查。
  • @Rup m 可以大于限制

标签: c# algorithm math


【解决方案1】:

我通常不编写 C#,因此与其在一些不连贯的 C# 意大利面条中磕磕绊绊,我将描述 C#-madeup-psuedo-code 的改进。

问题似乎出在您的GetDivisors 函数中。这是相对于每个除数 n 的线性 O(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)),这应该会显着提高速度。

【讨论】:

    【解决方案2】:

    有一个简单的公式可以给出一个知道素数分解的数的除数之和:

     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 的筛子很容易做到这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-13
      • 2010-10-22
      • 1970-01-01
      相关资源
      最近更新 更多