Returning String of prime factors in Java

别来无恙 提交于 2019-12-23 12:38:06

问题


I know this is a classic problem. I solved it in Java. I have my solution below. However, when I used this solution in codefights.com, It went beyond the execution time limit. I would appreciate if anyone could give me suggestions on improving this code in any way possible. Please feel free to criticize my code so that I can improve on my coding skills. Thanks

You're given number n.

Return n as a product of its prime factors.

Example

For n = 22 the output should be "2*11".

For n = 120 the output should be "2*2*2*3*5".

For n = 17194016 the output should be "2*2*2*2*2*7*59*1301".

[input] integer n

An integer number smaller than 109. [output] string

The Prime factors of n which splitted by * symbol. prime factors should be in increasing order.

Solution (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;
}

回答1:


Since n is smaller than a fixed number (109), simply use a table containing all prims <= 109, instead of generating them dynamically. Or atleast generate the prims first using the sieve of erathostenes or atkin. The hardcoded table would be preferable, but using a sieve for generating the table dynamically would aswell speed things up alot. The isPrime() function you implemented is a performance killer.




回答2:


The function isPrime() is called too much times in primefactors. For example, i == 2 and there are many divisors 2 in n. The top call (isPrime(i)) is fine. However, inside the loop while (n % i == 0) you check isPrime(n) after each dividing n /= 2;. So, if initial n is 100 the function isPrime() is called for 50 and on the next loop for 25. That does not make any sense. I think that it is the biggest problem here, since even if isPrime works in linear time it is too much to call it many times in the internal loop.

It is possible to exit from the loop for i in two cases: n is equal 1 after divisions or n is for sure prime if i is larger than 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;
}

Even after that improvement (and sqrt(n) as the max limit in isPrime()) your algorithm will have linear complexity O(n), since there are at most sqrt(n) loops for i and the maximum number of probes for prime in isPrime is also sqrt(n).


Yes, it can be done better by choosing better algorithms for isPrime(). Even if you are not allowed to use hardcoded table of prime numbers it is possible to generate such look up table in runtime (if there are enough memory). So, it is possible to use automatically generated list of primes organized in ascending order to probe given number up to sqrt(n). If i becomes larger than sqrt(n) it means that the next prime is found and it should be appended to the look up table and isPrime() should return true.

Example

Suppose isPrime is called for 113. At that moment the look up table has a list of previous prime numbers: 2,3,5,7,11,13.... So, we try to divide 113 by items from that list up to sqrt(113) (while (i <= 10)). After trying 2,3,5,7 the next item on the list 11 is too large, so 113 is appended to the list of primes and the function returns true.


The other algorithms may give better performance in the worst case. For example the sieve of Eratosthenes or sieve of Atkin can be used to effectively precomputed list of prime numbers up to given n with the best O(n) complexity for the best implementation. Here you need to find all primes up to sqrt(n), so it takes O(sqrt(n)) to generate such list. Once such list is generated you need to try to divide your input by numbers is the list that takes at most sqrt(n) probes. So, the algorithm complexity is O(sqrt(n)). However, suppose that your input is 1024 that is 2 to the power of 10. In that case the first algorithm will be better, since it will not go to primes larger than 2.


Do you really need the function isPrime()?

With flexible thinking If we look closer it appears that you do not have to search for all primes in some range. You only needed to find all prime divisors of one given integer. However if we try to divide n by all integers in range up to sqrt(n) that is also good solution. Even if such integer is not prime it will be skipped due to the condition n % i == 0, since all primes lower than the integer under test are already removed from n, so that simple modular division does here the same as isPrime(). The full solution with O(sqrt(n)) complexity:

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;
}

It is also possible to split the function to avoid if (n == 1) check in the inner loop, however it does not change the algorithm complexity.



来源:https://stackoverflow.com/questions/32914103/returning-string-of-prime-factors-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!