【问题标题】:Algorithm to check if a number if a perfect number检查一个数字是否是一个完美数字的算法
【发布时间】:2011-09-27 20:27:46
【问题描述】:

我正在寻找一种算法来确定给定数字是否为完美数字。

我想到的最简单的是:

  1. 找出数的所有因数
  2. 获取质因数[除了数字本身,如果它是质数]并将它们相加以检查它是否是一个完美的数字。

有没有更好的方法来做到这一点? 在搜索中,出现了一些 Euclids 工作,但没有找到任何好的算法。这个 Golfscript 也没有帮助:https://stackoverflow.com/questions/3472534/checking-whether-a-number-is-mathematically-a-perfect-number

数字等可以在现实世界使用中被缓存等[我不知道在哪里使用完美的号码:)]
但是,由于这是在面试中被问到的,我假设应该有一种“可推导”的方式来优化它。

谢谢!

【问题讨论】:

  • 请注意,对于您的第 2 步,它不是其 prime 因子的总和,而是 所有 因子的总和。例如。 28 是完美的,因为 1 + 2 + 4 + 7 + 14 = 28(注意 4 和 14 因素)。

标签: algorithm math perfect-numbers


【解决方案1】:

如果输入是偶数,看看是不是2^(p-1)*(2^p-1)的形式,p2^p-1是素数。

如果输入是奇数,则返回“false”。 :-)

详情请参阅Wikipedia page

(实际上,由于少于 2500 万位的完美数字只有 47 个,因此您可以从一个简单的表格开始。询问面试官您是否可以假设您使用的是 64 位数字,例如... )

【讨论】:

  • 一直在这样的面试问题的两端,我有点想知道他们是否期待像表格答案这样的东西。它似乎在询问非常具体的知识。我想要的是会编程的人,而不是懂数论的人。
  • 注意梅森数 (2^p)-1 素数的专用 Lucas-Lehmer test
  • 感谢链接。我认为没有可推导出的优化......所以如果使用表格不起作用......那么面试官可能需要一个可以编写代码的数学家,而不是一个可以使用数学的程序员!
  • Odd perfect numbers are larger than 10**1500 if they exist. (2012) 即,在开始担心奇完美数之前,您需要 >4Kbit 整数。
  • 只有前 43 个数字不包含空白,即,有 48 个(2013 年)已知的完美数字(与 Mersenne primes 一对一的关系)但在最后 5 个之间可能还有其他数字.
【解决方案2】:

编辑:该死,我没有通过面试! :-(
在我过分热心地尝试寻找技巧或启发式方法来改进“因式分解 + 枚举除数 + 求和”方法时,我没有注意到 1 模 9 仅仅是必要的,当然不是充分条件 at 数字(6 除外)是完美的...
呃……平均九分之一的偶数满足这个条件,我的算法肯定会找到太多完美的数字;-)。
为了救赎自己,坚持并维持使用数字根的建议,但仅作为过滤器,以避免在大多数情况下对因子进行更昂贵的计算。


[原尝试:耻辱殿]

If the number is even,<br>
   compute its [digital root][1].
       if the digital root is 1, the number is perfect, otherwise it isn't.

If the number is odd...
   there are no shortcuts, other than...
       "Not perfect" if the number is smaller than 10^300
       For bigger values, one would then need to run the algorithm described in 
       the question, possibly with a few twists typically driven by heuristics
       that prove that the sum of divisors will be lacking when the number
       doesn't have some of the low prime factors.

我建议偶数的数字根技巧的原因是,这个可以在没有任意长度的算术库(如 GMP)的帮助下计算。它也计算成本低得多 比分解素因子和/或分解 (2^(p-1) * ((2^p)-1))。因此,如果面试官对奇数的“不完美”回答感到满意,那么该解决方案在大多数计算机语言中都是非常有效且可编码的。


[第二次和第三次尝试...]

If the number is even,<br>
   if it is 6
      The number is PERFECT
   otherwise compute its [digital root][1].
       if the digital root is _not_ 1
           The number is NOT PERFECT
       else ..., 
           Compute the prime factors
           Enumerate the divisors, sum them
           if the sum of these divisor equals the 2 * the number
                it is PERFECT
           else
                it is NOT PERFECT

If the number is odd...
    same as previously

关于这个比较奇怪的面试问题……
我同意 andrewdski 对这篇文章中另一个回复的评论,认为这个特殊问题在通用开发人员的面试中相当奇怪。
与许多面试问题一样,它可以是面试官不是在寻求特定的解决方案,而是为候选人提供一个机会来展示他/她表达各种方法的一般利弊的能力。此外,如果候选人有机会在回复之前查找通用资源,例如 MathWorld 或 Wikipedia,这也可能是对他/她快速理解那里提供的信息的能力的一个很好的测试。

【讨论】:

  • 嗯。 6 的数字根是... 6。我可以发誓 6 是第一个完美数字。是的,数字根技巧适用于超过 1 位的完美数字。但这只是完美数的必要条件。 10 的数字根也是 1,我可以发誓 10 并不完美。
  • @woodchips:谢谢你让我回到现实。当某些事情看起来好得令人难以置信时,通常就是这种情况。有了完美数与梅森数的所有联系(除了数字根测试本质上是一个模 9 测试之外),我应该认为它不会那么容易:-(
  • 您的第二种算法更好,允许您排除大约 90% 的偶数,因为它们可能不完美。但是它仍然会错过将 6 识别为完美数字,因为 6 的数字根是 6,而不是 1。
  • @woodchips 再次感谢。我相应地修复了。也许我应该在这个阳光明媚的 7 月 4 日远离算法……
【解决方案3】:

这是一个快速的算法,只是为了好玩,在 PHP 中 - 只使用一个简单的 for 循环。您可以轻松地将其移植到其他语言:

function isPerfectNumber($num) {
        $out = false;

        if($num%2 == 0) {
            $divisors = array(1);
            for($i=2; $i<$num; $i++) {
                if($num%$i == 0)
                    $divisors[] = $i;
            }

            if(array_sum($divisors) == $num)
                $out = true;
        }

        return $out ? 'It\'s perfect!' : 'Not a perfect number.';
    }

希望这会有所帮助,不确定这是否是您要找的。​​p>

【讨论】:

  • 虽然在功能上是正确的,但这个实现远非最佳,但它的主要缺点是它的操作范围绑定到 PHP 整数的范围,而在完美数 / mersennes 的世界中,它是一个相当小的数字; -) 如果你想超过 2^PHP_INT_SIZE 限制,你应该使用 GMP(任意长度整数)。
  • thnx,我一直在寻找一些更快的方法来做到这一点。获得更大的数字会很慢?
  • 在找到除数后立即添加除数而不是保存并稍后添加不是更有意义吗?另外,看到 i 从 2 开始,if 条件不应该是 $sum+1 == $num
【解决方案4】:
#include<stdio.h>
#include<stdlib.h>
int sumOfFactors(int ); 

int main(){
int x, start, end;
    printf("Enter start of the range:\n");
    scanf("%d", &start);
    printf("Enter end of the range:\n");
    scanf("%d", &end);

    for(x = start;x <= end;x++){
        if(x == sumOfFactors(x)){
            printf("The numbers %d is a perfect number\n", x);
        }
    }   
    return 0;
}

int sumOfFactors(int x){
    int sum = 1, i, j;
    for(j=2;j <= x/2;j++){
        if(x % j == 0)
            sum += j;
    }
    return sum;
}

【讨论】:

    猜你喜欢
    • 2017-01-09
    • 2015-11-06
    • 2022-01-17
    • 1970-01-01
    • 2016-06-15
    • 1970-01-01
    • 2015-09-15
    相关资源
    最近更新 更多