返回Java中的素数因子串

时间:2015-10-02 19:02:05

标签: java prime-factoring

我知道这是一个经典问题。我用Java解决了它。我的解决方案如下。但是,当我在codefights.com中使用此解决方案时,它超出了执行时间限制。如果有人能以任何可能的方式向我提出改进此代码的建议,我将不胜感激。请随意批评我的代码,以便我可以提高我的编码技能。谢谢

  

你的号码为n。

     

将n作为其主要因素的产物返回。

     

实施例

     

对于n = 22,输出应为“2 * 11”。

     

对于n = 120,输出应为“2 * 2 * 2 * 3 * 5”。

     

对于n = 17194016,输出应为“2 * 2 * 2 * 2 * 2 * 7 * 59 * 1301”。

     

[输入]整数n

     

小于109的整数。[output] string

     

由*符号分割的n的素数因子。主要原因   应该按顺序递增。

解决方案(JAVA):

public String primefactors(int n) {
    String factors = "";

    for (int i = 2; i <= n / 2; i++) {
        if (isPrime(i)) {
            while (n % i == 0) {
                n /= i;
                if (isPrime(n) && n != 1) {
                    factors = factors + Integer.valueOf(i).toString() + "*"
                            + Integer.valueOf(n).toString();
                    break;
                } else if (n == 1)
                    factors = factors + Integer.valueOf(i).toString();
                else
                    factors = factors + Integer.valueOf(i).toString() + "*";
            }
        }
    }
    return factors;
}

public boolean isPrime(int n) {
    boolean prime = true;
    if (n == 1)
        return false;
    else if (n % 2 == 0 && n!=2)
        return false;
    else if (n % 3 == 0 && n!=3)
        return false;
    else {
        for (int j = 2; j < n / 2; j++) {
            if (n % j == 0) {
                return false;
            }
        }
    }
    return prime;
}

2 个答案:

答案 0 :(得分:2)

由于n小于固定数字(109),只需使用包含所有prims&lt; = 109的表,而不是动态生成它们。或至少首先使用erathostenes或atkin的筛子产生prims。硬编码表会更好,但使用筛子动态生成表格也会加快速度。您实施的isPrime()功能是性能杀手。

答案 1 :(得分:1)

isPrime()中调用函数primefactors太多次了。例如,i == 2 2中有许多除数n。热门电话(isPrime(i))很好。但是,在循环while (n % i == 0)内,您在每次分割isPrime(n)后检查n /= 2;。因此,如果初始n100,则为isPrime()调用函数50,并在25的下一个循环调用函数isPrime。这没有任何意义。我认为这是最大的问题,因为即使i在线性时间内工作,在内部循环中多次调用它也是太多了。

在两种情况下可以退出n的循环:1在分割后等于ni肯定是sqrt(n) }大于public String primefactors(int n) { String factors = ""; int max_divisor = sqrt(n); for (int i = 2; i <= max_divisor; i++) { if (isPrime(i)) { while (n % i == 0) { n /= i; if (n == 1) factors = factors + Integer.valueOf(i).toString(); else factors = factors + Integer.valueOf(i).toString() + "*"; } max_divisor = sqrt(n); } } // check for the last prime divisor if (n != 1) factors = factors + Integer.valueOf(n).toString(); return factors; }

sqrt(n)

即使在改进之后(并isPrime()作为O(n)中的最大限制),您的算法也会有线性复杂度sqrt(n),因为{最多i个圈{ {1}} isPrime中素数的最大探测数也是sqrt(n)

是的,通过为isPrime()选择更好的算法可以做得更好。即使您不允许使用硬编码的素数表,也可以在运行时生成这样的查找表(如果有足够的内存)。因此,可以使用按升序组织的自动生成的素数列表来探测给定的数字,直到sqrt(n)。如果i大于sqrt(n),则表示找到了下一个素数,并且应将其附加到查找表中,isPrime()应返回true

实施例

假设为isPrime调用113。此时,查找表中包含先前素数的列表:2,3,5,7,11,13...。因此,我们尝试将113除以该列表中的项目分为sqrt(113)while (i <= 10))。在尝试2,3,5,7后,列表11上的下一个项目太大,因此113会附加到素数列表中,函数会返回true

在最坏的情况下,其他算法可能会提供更好的性能。例如,Eratosthenes筛或Atkin筛可用于有效预先计算的素数列表,直到给定n,具有最佳O(n)复杂度,以实现最佳实施。在这里,您需要查找最多sqrt(n)的所有素数,因此生成此类列表需要O(sqrt(n))。一旦生成了这样的列表,您需要尝试按数字划分您的输入是最多需要sqrt(n)探测的列表。因此,算法复杂度为O(sqrt(n))。但是,假设您的输入为1024210的幂。在这种情况下,第一个算法会更好,因为它不会转到大于2的素数。

你真的需要函数isPrime()吗?

灵活思考如果我们仔细观察,您似乎不必在某个范围内搜索所有素数。您只需要找到一个给定整数的所有素数除数。但是,如果我们尝试将n除以所有整数,范围最高为sqrt(n),这也是一个很好的解决方案。即使这样的整数不是素数,它也会因条件n % i == 0而被跳过,因为所有低于被测整数的质数都已从n中删除,因此简单的模块化除法在此处与isPrime()。具有O(sqrt(n))复杂度的完整解决方案:

public String primefactors(int n) {
    String factors = "";
    int max_divisor = sqrt(n);
    for (int i = 2; i <= max_divisor; i++) {
        while (n % i == 0) {
            n /= i;
            max_divisor = sqrt(n);
            if (n == 1)
                factors = factors + Integer.valueOf(i).toString();
            else
                factors = factors + Integer.valueOf(i).toString() + "*";
        }
    }
    // check for the last prime divisor
    if (n != 1)
        factors = factors + Integer.valueOf(n).toString();

    return factors;
}

也可以拆分函数以避免在内循环中进行if (n == 1)检查,但是它不会改变算法的复杂性。