You really do find prime numbers?

You really do find prime numbers?


Definition of primes looks very simple, if only if a number is divisible by 1 and itself, then this number is prime.

Lianqi

Do not think that the definition of prime numbers is simple, really I am afraid not many people can prime related write efficient algorithms. For example, let you write a function like this:

// 返回区间 [2, n) 中有几个素数 
int countPrimes(int n)

// 比如 countPrimes(10) 返回 4
// 因为 2,3,5,7 是素数

How would you write this function? I think we should write:

int countPrimes(int n) {
    int count = 0;
    for (int i = 2; i < n; i++)
        if (isPrim(i)) count++;
    return count;
}

// 判断整数 n 是否是素数
boolean isPrime(int n) {
    for (int i = 2; i < n; i++)
        if (n % i == 0)
            // 有其他整除因子
            return false;
    return true;
}

Such words written complexity of time O ( n 2 ) O (n ^ 2) , a big problem. First, you use the function to assist isPrime idea is not enough and efficient;

And even if you use isPrime function, write algorithms also exist to calculate redundancy.

Saver

Simply under the first-come, if you want to determine if a number is not prime, how to write algorithms. Just slightly modify the above isPrim code for cycling conditions:

boolean isPrime(int n) {
    for (int i = 2; i * i <= n; i++)
        ...
}

In other words, i not need to traverse to n, and only need to sqrt (n) can be. Why, we give an example, suppose n = 12.

12 = 2 × 6
12 = 3 × 4
12 = sqrt(12) × sqrt(12)
12 = 4 × 3
12 = 6 × 2

It can be seen that the product of the two first two, in turn, reverse the critical point in sqrt (n).
In other words, if [2, sqrt (n)] is found within this interval of divisible factors, we can directly conclude that n is a prime number, because in the interval [sqrt (n), n] will not be found to be divisible factor.

Now, time is a function of the complexity of the isPrime reduced to O (sqrt (N)), but we realize countPrimes function actually do not need this function, more than just hope that readers understand the meaning of sqrt (n), because, etc. will also be used.

Mahayana

Efficient Implementation countPrimes

The core development of an effective solution to this problem is and conventional thinking above Anti forward to:
First, from the start 2, we know that 2 is a prime number, then the 2 × 2 = 4, 3 × 2 = 6, 4 × 2 = 8 ... not It may be a prime number.
Then we also found 3 prime number, then the 3 × 2 = 6, 3 × 3 = 9, 3 × 4 = 12 ... are also not be a prime number.

See here, if you understand a little bit of logic of the exclusion of it? We look at the first version of the code:

int countPrimes(int n) {
    boolean[] isPrim = new boolean[n];
    // 将数组都初始化为 true
    Arrays.fill(isPrim, true);

    for (int i = 2; i < n; i++) 
        if (isPrim[i]) 
            // i 的倍数不可能是素数了
            for (int j = 2 * i; j < n; j += i) 
                    isPrim[j] = false;

    int count = 0;
    for (int i = 2; i < n; i++)
        if (isPrim[i]) count++;

    return count;
}

If the above code you can understand, then you've mastered the whole idea, but there are two minor areas can be optimized.

Soaring period

First, recall just determining whether a number is a prime number isPrime function, due to the symmetry factor, which need only to traverse the loop for [2,sqrt(n)]enough. Here is similar, our outer for loop 只需要遍历到 sqrt(n):

for (int i = 2; i * i < n; i++) 
    if (isPrim[i]) 
        ...

In addition, hardly notice the inner for loop can be optimized. Our previous approach is:

for (int j = 2 * i; j < n; j += i) 
    isPrim[j] = false;

This in turn can have an integer multiple i flag is false, there remains a redundancy calculation.

For example n = 25, i = algorithm mark 4 4 × 2 = 8,4 × 3 = 12 numbers, etc., but the two figures have been i = 2 and i = 3 of 2 × 4 and 3 × 4 marks a.

We can optimize a little bit and let j i start from square traversal, instead of from 2 * i start:

for (int j = i * i; j < n; j += i) 
    isPrim[j] = false;

Thus, the prime counting on the efficient implementation of the algorithm, in fact, this algorithm has a name, called the Sieve of Eratosthenes. Look at the complete final code:

int countPrimes(int n) {
    boolean[] isPrim = new boolean[n];
    Arrays.fill(isPrim, true);
    for (int i = 2; i * i < n; i++) 
        if (isPrim[i]) 
            for (int j = i * i; j < n; j += i) 
                isPrim[j] = false;

    int count = 0;
    for (int i = 2; i < n; i++)
        if (isPrim[i]) count++;

    return count;
}

The time complexity of the algorithm is considered more difficult, obviously with time for the two nested loop about which operand should be:
n-/ n-2 + / +. 3 n-/ n-+. 5 /. 7 + ... = n-× ( 1/2 + 1/3 + 1/5 + 1 / ... 7)
in parentheses is the reciprocal prime number. The end result is O ( N l O g l O g N ) O (N * loglogN) , interested readers can check out the time complexity of the algorithm is proved.

Published 126 original articles · won praise 57 · views 90000 +

Guess you like

Origin blog.csdn.net/wolfGuiDao/article/details/104952718