【LeetCode】Statistics of prime numbers (prime numbers) within N

Title

Given a value n, count the number of prime numbers within 2~n
Explanation:
Prime numbers are prime numbers. A natural number other than 0 and 1 that is only divisible by 1 and itself is a prime number.
Example:
Input: 100
Output: 25

Solution

Method 1: (violent solution)

train of thought

Start traversing directly from 2, and judge whether it can be divisible by the number between 2 and itself

code example

public class CountPrime {
    
    

    public static void main(String[] args) {
    
    
        System.out.println(countPrime(100));
    }

    private static int countPrime(int n) {
    
    
        int count = 0;
        for (int i = 2; i < n; i++) {
    
    
            if (isPrime(i)) {
    
    
                count++;
            }
        }

        return count;
    }

    /**
     * 判断输入的数是否为质数
     *
     * @param x 输入的数
     * @return true:是;false:否
     */
    private static boolean isPrime(int x) {
    
    

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

Improve ideas

Although the above violent solution can be used, there are still places that can be optimized. Why, because of the existence of [Multiplication Associative Law].

2 * 50=100; 50 * 2 = 100;
4 * 25=100; 25 * 4 = 100;
and so on. If a is divisible by x to get b, then b is also divisible by x to get a

Therefore, it can be said that because of the [Multiplication Associativity Law], when we calculate whether a number is divisible by a certain number, we don’t need to traverse completely, we only need to traverse to the root sign x, as shown in the following figure: (but The root sign x is not easy to express, so in another way, i * i <= x)

    private static boolean isPrime(int x) {
    
    

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

Method 2: (England screening method)

train of thought

Using the concept of composite numbers (non-prime numbers), the prime number *m must be a composite number, so you can traverse from 2, mark all the composite numbers, and exchange space for time. What does that mean?
For example, if 3 is a prime number, then there must be the following rules:

3 * 2 = 6; Composite number
3 * 3 = 9; Composite number
3 * 4 = 12; Composite number
3 * 5 = 15; Composite number
and so on, 3 * m must be a composite number, until 3 * m < n. mark these in advance

code example

public class CountPrime {
    
    

    public static void main(String[] args) {
    
    
        System.out.println(eratosthenes(100));
    }

    /**
     * 判断输入的数是否为质数
     *
     * @param x 输入的数
     * @return true:是;false:否
     */
    private static int eratosthenes(int x) {
    
    
        boolean[] isPrime = new boolean[x];
        int count = 0;
        for (int i = 2; i < x; i++) {
    
    
            if (!isPrime[i]) {
    
    
                count++;

                // 标记合数
                for (int j = 2 * i; j < x; j += i) {
    
    
                    isPrime[j] = true;
                }
            }
        }
        return count;
    }
}

You may not be able to react to the above marked composite number cycle. j+=iThe principle is 【Additional Distributive Law】. 3 * i = (2 + 1) * i = 2 * i + 1 * i. Therefore, in order to accumulate the coefficient m of i, +iit is ok every time.

Improve ideas

The above algorithm can continue to be improved, which is similar to the improvement idea of ​​method 1. When the inner loop marks a composite number, there is a case of repeated marking. For example: (Assume that the input n=100)

  1. At that timei=2 , it will be marked 2 * k (k>=2, 2 * k < x) , that is , at least elements 2 * 2,2 * 3,2 * 4,··· 2 * 50have been marked ;50 - 2 + 1
  2. At that timei=3 , it will be marked 3 * k (k>=2, 3 * k < x) , that is , at least elements 3 * 2,3 * 3,3 * 4,··· 3 * 33have been marked ;33 - 2 + 1
  3. At that timei=4 , it will be marked 4 * k (k>=2, 4 * k < x) , that is , at least elements 4 * 2,4 * 3,4 * 4,··· 4 * 25have been marked .25 - 2 + 1
  4. At that timei=5 , it will be marked 5 * k (k>=2, 5 * k < x), in fact, 5 * 3it was marked earlier; 5 * 4 = 20, it i =2was marked as early as when

Obviously, if we mark step by step, there will definitely be crossover and redundant marks.
From the above description, we can conclude a rule, when i > 2, (2 * i) ~ (i-1) * ithe part must have been marked. So, modify the inner loop algorithm as follows:

        private static int eratosthenes(int x) {
    
    
        long start = System.currentTimeMillis();

        // 默认全部标记为素数
        boolean[] isNotPrime = new boolean[x];
        int count = 0;

        outer:
        for (int i = 2; i < x; i++) {
    
    
            if (!isNotPrime[i]) {
    
    
                count++;

                // 标记合数
                for (int j = i * i; j > 0 && j < x; j += i) {
    
    
                    isNotPrime[j] = true;
                }
            }
        }

        System.out.println("耗时:" + (System.currentTimeMillis()-start));
        return count;
    }

Note: When i is relatively large, there may be i * i > Integer.MAX_VALUEsituations, so judgment is required j > 0to continue the operation

Guess you like

Origin blog.csdn.net/qq_32681589/article/details/132059584