How can I improve this code for Project Euler 7?

女生的网名这么多〃 提交于 2019-12-02 03:58:08
corsiKa

You need to test the number against every prime less than its square root to ensure it is prime.

You're only testing against 2,3 and 5.

Because storing all the primes is not always space-feasable, a common technique is to test for 2, and then test all odd numbers starting at 3. This requires a loop.

consider:

boolean isPrime(long n) {
    if (n < 2) return false;
    if (n == 2) return true;
    if (n % 2 == 0) return false;
    if (n < 9) return true;
    if (n % 3 == 0) return false;
    long max = (long)(Math.sqrt(n + 0.0)) + 1;
    for (int i = 5; i <= max; i += 6) {
        if (n % i == 0) return false;
        if (n % (i + 2) == 0) return false;
    }
    return true;
}

A number p is prime if it only divides by itself and 1. You are checking only for divison by 2, 3 and 5. This is not enough. Check for every number till p / 2, or better till sqrt(p).

The following solution checks only the odd numbers to be prime, but it counts 2 as prime from the beginning:

public class A {

    static int N = 10001;

    private static boolean isOddPrime(long x) {

        for ( int i = 3 ; i*i <= x ; i+=2 ) {
            if ( x % i == 0 ) {
                return false;
            }               
        }
        return true;
    }

    public static void main(String[] args) throws Exception {
        long start = System.nanoTime();
        int x;
        int i = 2;      // 3 is the 2nd prime number
        for ( x = 3 ; ; x+=2 ) {
            if ( isOddPrime(x) ) {              
                if ( i == N )
                    break;
                i++;
            }
        }
        System.out.println(x);

        long stop = System.nanoTime();
        System.out.println("Time: " + (stop - start) / 1000000 + " ms");
    }
}

Output:

104743
Time: 61 ms

I would comment, but I just joined.

You don't have to check every number between 1 and a numbers square root for potential divisors, you just have to check all previous primes (assuming you start at 1 and iterate up), as any other divisor that is not prime will itself be divisible by a prime of a lower value. the higher the number of primes, the more checks against non prime numbers this saves. the example is in C# but that's more to demonstrate the concept.

    //store found primes here, for checking subsequent primes
    private static List<long> Primes;
    private static bool IsPrime(long number)
    {
        //no number will have a larger divisor withou some smaller divisor
        var maxPrime = Math.Sqrt(number);

        // takes the list of primes less than the square root and 
        //     checks to see if all of that list is not evenly 
        //     divisible into {number}
        var isPrime = Primes
            .TakeWhile(prime => !(prime > maxPrime))
            .All(prime => number % prime != 0);
        if (isPrime)
            Primes.Add(number);
        return isPrime;
    }

    private static long GetNthPrime(int n)
    {
        //reset primes list to prevent persistence
        Primes = new List<long> { 2, 3, 5, 7 };

        //prime in starting set
        if (Primes.Count >= n)
        {
            return Primes[n - 1];
        }

        //iterate by 6 to avoid all divisiors of 2 and 3 
        //  (also have to check i + 2 for this to work)
        //  similar to incrementing by 2 but skips every third increment 
        //  starting with the second, as that is divisible by 3
        for (long i = 11; i < long.MaxValue; i += 6)
        {
            // only check count if is prime
            if ((IsPrime(i) && Primes.Count >= n) || (IsPrime(i + 2) && Primes.Count >= n))
            {
                break;
            };
        }
        //return end of list
        return Primes[n - 1];
    }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!