给定范围内的素数,复杂度较低

时间:2015-10-25 13:59:09

标签: java

我使用下面的程序来找到前n个素数(在下面的程序中它是从2到n)。我们可以用单个for循环编写一个程序吗?我也试过递归方法,但它对我不起作用。

T(0,...,0)

3 个答案:

答案 0 :(得分:1)

我认为你不能把它减少到一个循环。但是你可以像Luca提到的那样改进你的代码。

public class PrimeFinder {

    private final List<Integer> primes;
    private final int primeCapacity;

    public PrimeFinder(final int primeCapacity) {
        if (primeCapacity < 3) {
            throw new IllegalArgumentException("Tkat is way to easy.");
        }
        this.primeCapacity = primeCapacity;
        primes = new ArrayList<>(primeCapacity);
        primes.add(2);
    }

    public void find() {
        final Index currentNumber = new Index();
        while (primes.size() < primeCapacity) {
            if (!primes.stream().parallel().anyMatch(prime ->  (currentNumber.value % prime) == 0)) {
                primes.add(currentNumber.incremet());
            } else {
                currentNumber.incremet();
            }
        }
    }

    public List<Integer> getPrimes() {
        return primes;
    }

    private class Index {

        public int value = 3;

        public int incremet() {

            return value++;

        }
    }

    public static void main(String[] args) {
        PrimeFinder primeFinder = new PrimeFinder(100000);
        final long start = System.currentTimeMillis();
        primeFinder.find();
        final long finish = System.currentTimeMillis();
        System.out.println("Score after " + (finish - start) + " milis.");
        primeFinder.getPrimes().stream().forEach((prime) -> {
            System.out.println(prime);
        });

    }
}

这里的主要规则很简单,如果给定的数字没有明显除以您已经找到的任何素数,那么它就是素数。

P.S。不要忘记primes.strem()....也是循环,所以它不是一个循环代码。

P.S.S。你可以进一步减少这一点。

答案 1 :(得分:0)

要了解算法的复杂性,您不必计算内部循环的数量,而是计算迭代元素的次数。要提高算法的性能,您需要调查是否存在一些不必要的迭代。 在你的情况下,当你这样做 for(int i = 2; i&lt; = num / 2; i ++)你正在测试你的num对不必要的值。例如:如果一个数字可以被4整除,那么它也将是2。

当你为(int i = 2; i&lt; = num / 2; i ++)做num = 11时 我将假设值2,3,4,5。 4这里是一个没有趣的数字,代表了一个可以避免的迭代。

无论如何根据维基百科,Eratosthenes的筛子是找到所有较小素数的最有效方法之一。

public class PrimeSieve {
public static void main(String[] args) { 
    int N = Integer.parseInt(args[0]);

    // initially assume all integers are prime
    boolean[] isPrime = new boolean[N + 1];
    for (int i = 2; i <= N; i++) {
        isPrime[i] = true;
    }

    // mark non-primes <= N using Sieve of Eratosthenes
    for (int i = 2; i*i <= N; i++) {

        // if i is prime, then mark multiples of i as nonprime
        // suffices to consider mutiples i, i+1, ..., N/i
        if (isPrime[i]) {
            for (int j = i; i*j <= N; j++) {
                isPrime[i*j] = false;
            }
        }
    }

    // count primes
    int primes = 0;
    for (int i = 2; i <= N; i++) {
        if (isPrime[i]) primes++;
    }
    System.out.println("The number of primes <= " + N + " is " + primes);
}
}

答案 2 :(得分:0)

我不知道如何使用单个循环来解决您的问题,但我确实看到了两个可以降低复杂性的地方:

  1. 缓存找到的素数并使用这些素数来判断数字是否为素数。例如,要确定11是否为素数,您只需将其除以2,3,5,7而不是2,3,4,5,6,...... 10

  2. 你不需要检查到num / 2,你只需要检查直到num的平方根。例如,对于10,您只需要检查2,3而不是2,3,4,5。因为如果数字n不是素数,则n = a * b,其中a或b小于n的平方根x。如果a是较小的一个,知道n可以除以a足以判断n不是素数。

  3. 所以结合1&amp; 2,你可以提高你的循环效率:

    public static void main(String[] args) {
        // Prime numbers in a range
        int range = 15;
        int num = 1;
        int count = 0;
        boolean prime = true;
    
        ArrayList<Integer> primes = new ArrayList<>(range);
    
        while (num < range) {
            num = num + 1;
            prime = true;
            int numSquareRoot = (int) Math.floor(Math.pow(num, 0.5));
            for (Integer smallPrimes : primes) {// only need to divide by the primes smaller than num
                if (numSquareRoot > numSquareRoot) {// only need to check till the square root of num
                    break;
                }
                if (num % smallPrimes == 0) {
                    prime = false;
                    break;
                }
            }
    
            if (prime) {
                System.out.println(num);
                primes.add(num);// cache the primes
            }
        }
    }