最小可能数被X以下所有数均分的最佳算法

时间:2019-06-25 17:49:55

标签: java algorithm performance

这是我为问题5项目Euler寻找性能良好的算法的尝试-找到均匀可分x的小号可能数和x以下的所有数。

我尝试使用一个循环使#s和另一个循环来测试该数字是否可以被x和x以下的所有#s整除

System.out.println("This program finds the smallest positive "
                + "number that");
        System.out.println("is evenly divisible by all of the numbers "
                + "from 1 to N.");
        System.out.print("Enter N: ");
        int N=kb.nextInt();
        long bigN=1;
        for(int i=1;i<=N;i++){
            bigN=bigN*i;
            /*bigN serves as a definite end for our loop
            when trying to find all #s divisible from 1 to n
            */
        }
        long smallestAnswer=bigN;
        int count=0;
        for(long i=1;i<=bigN;i++){//# being tested
            for(int j=1;j<=N;j++){//test
                if(i%j==0){
                    count++;
                }
                if(count==N && i<smallestAnswer){
                smallestAnswer=i;//should catch only the first/smallest answer
                break;
                }
            }
            count=0;
        }
        System.out.printf("\nThe smallest # evenly divisible by all of the "
                + "numbers from 1 to N");
        System.out.printf("\nis %,d\n",smallestAnswer);
    }

该代码有效。没有运行/编译时间错误。太慢了。如果用户输入的#大于11,则代码基本上会冻结

2 个答案:

答案 0 :(得分:5)

您正在使用蛮力算法。就像在Euler项目上发现的那样,挑战通常是寻找正确算法的挑战,而不仅仅是编写代码的挑战。

这里的挑战是要找到从1到X的所有数字中的最小公倍数(请参见Wikipedia)。

示例:如果X为10,解决它的一种方法是确定除数:

 1 = 1
 2 = 2
 3 = 3     
 4 = 2^2
 5 = 5
 6 = 2 * 3
 7 = 7
 8 = 2^3
 9 = 3^2
10 = 2 * 5

因此,最小公倍数的除数为:

1 * 2^3 * 3^2 * 5 * 7  =  1 * 8 * 9 * 5 * 7 = 2520

由于这是您要解决的挑战,因此我将把编码留给您。

答案 1 :(得分:1)

我不太确定您为什么要为性能而苦苦挣扎。

$ date && X 20 && date
Tue Jun 25 13:18:13 CDT 2019
N: 20
232792560 is divisible by all numbers 1 to 20
Tue Jun 25 13:18:16 CDT 2019

3秒(N == 20)。

您要为每个检查的数字做额外的数学运算-很多额外的数学运算。首先,您可以从2到N,而不是对从1到N的每个数字进行检查,因为所有数字都可以被1整除。但是更重要的是,即使一个数字失败,您也将执行ALL。如果您转过这一部分,则在模数检查失败后就会中断“此数字是否起作用”代码。在N = 20时,这将为您节省18个对所有奇数的校验。

您还可以获得更多改进。该数字必须是偶数。因此,如果n> 1,则可以从2开始并以2而不是1递增。如果n> = 3,则实际上可以从6开始,然后增加6,从而节省了大量数学运算。如果n> = 4,则可以从12开始,再增加12。

作为参考,这是我的实现。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    int n = atoi(argv[1]);
    long trying = 1;
    bool found = false;

    while(!found) {
        found = true;
        ++trying;

        for (long checkDivide = 2; checkDivide <= n; +checkDivide) {
            if (trying % checkDivide != 0) {
                found = false;
                break;
            }
        }
    }

    printf("%ld is divisible by all numbers 1 to %d\n", trying, n);

    return 0;
}

我跳过了输入请求,只是将值放在命令行上。

请注意,逆转检查也可能更有效。也就是说,从n开始检查并降低到2。X%20的失败率要比X%2更高。我没有使用足够的时间检查分辨率来确保效率更高。