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+=i
The principle is 【Additional Distributive Law】. 3 * i = (2 + 1) * i = 2 * i + 1 * i
. Therefore, in order to accumulate the coefficient m of i, +i
it 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)
- At that time
i=2
, it will be marked2 * k (k>=2, 2 * k < x)
, that is , at least elements2 * 2,2 * 3,2 * 4,··· 2 * 50
have been marked ;50 - 2 + 1
- At that time
i=3
, it will be marked3 * k (k>=2, 3 * k < x)
, that is , at least elements3 * 2,3 * 3,3 * 4,··· 3 * 33
have been marked ;33 - 2 + 1
- At that time
i=4
, it will be marked4 * k (k>=2, 4 * k < x)
, that is , at least elements4 * 2,4 * 3,4 * 4,··· 4 * 25
have been marked .25 - 2 + 1
- At that time
i=5
, it will be marked5 * k (k>=2, 5 * k < x)
, in fact,5 * 3
it was marked earlier;5 * 4 = 20
, iti =2
was 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) * i
the 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_VALUE
situations, so judgment is required j > 0
to continue the operation