Prime numbers within 1000 (quality numbers)

1. What is a prime number (prime number)?

Among the natural numbers greater than 1, there are no other natural numbers except 1 and itself. It means: it can only be divisible by 1 and itself .

Two, problem-solving ideas

Double for loop, the first layer grows from 2 to 1000, the second layer tries to take the remainder, and there is a divisor, which is regarded as a non-prime number.

for ($i = 2; $i < 1001; $i++) {
    
    
    for ($j = 2; $j < $i; $j++) {
    
    
        if ($i % $j === 0) {
    
    
            continue 2;
        }
    }
    echo $i . ',';
}

This method is easy to understand and the speed is good. But things are certainly not that simple.

Three, a better way?

After all, I'm still not good at algorithms. I want to see how others do it, but Baidu and Google have a look. The answer is basically

<?php
for($i = 2; $i < 1001; $i++) {
    
    
 $primes = 0;
 for($k = 1; $k <= $i; $k++)
 if($i%$k === 0) $primes++;
 if($primes <= 2) // 能除以1和自身的整数(不包括0)
 echo "<strong>{
      
      $i}</strong><br />";
}

Who wrote it! It's too bad. One is necessary to divide 1 and itself, and the other is that the second layer increments to its own size every time.

Four, optimization

Think about it for yourself. Although I have not done many questions, I also know dynamic programming. I vaguely feel that every number behind will be related to the front.

Oh! If there is a remainder after dividing by 2, there is no need to divide by 4, and if there is a remainder after dividing by 3, there is no need to divide by 9, and so on. The prime numbers obtained before can be used. Declare an array of prime numbers, first verify whether it can be divisible by the numbers in the prime array. If none is divisible, the starting position of the second-level for loop changes, starting from the previous prime number after the first number.

// 如果数组是空的,第一次++$item会报错,所以第一个素数2直接放在数组里。
$arr = [2];

for ($i = 3; $i < 1001; $i++) {
    
    

    foreach ($arr as $item) {
    
    
        if ($i % $item === 0) {
    
    
            continue 2;
        }
    }

    for ($j = ++$item; $j < $i; $j++) {
    
    
        if ($i % $j === 0) {
    
    
            continue 2;
        }
    }

    $arr[] = $i;
}

Well, test, no problem.

Let's take a look at the speed of these three methods (in order of the online method, my first edition, after optimization), 1000 is too small, change to 1W.

Insert picture description here
The speed difference between the first and the second is 9 times, and the speed difference between the second and the third is 7 times.

Remove the first method and test again with 10W.
Insert picture description here
The speed difference is 9 times.

Five, re-optimize

# Think again? One of the prime numbers is very special, that is 2, it is the only even number, and the rest are odd numbers. So every time you can increment by 2 and $i++you can change $i += 2it to , since it will be an odd number afterwards, you don’t always have to try to divide by 2 first.

# Think about it again? According to the previous idea, the second level of for loop ++$itemshould be changed to add 2 each time. Of course, this is the same as the previous point of optimization, and the initial effect is quite weak.

# Think about it again? Well, print out these prime numbers first and find the pattern. . . . . Hey! Divide, I foreach traverse all prime number arrays, what’s wrong here, when the dividend traverses more than half of the current verification number, it is impossible to be divisible! Add judgment$item < count($arr) / 2

# Think about it again? Well,, according to the previous idea, why must it be half, and 1/3 is not allowed. If 1/3 can be divisible by 3, and so on, 1/5, 1/7, 1/11 … When is the head? Well, it should be rooted. When $i / sqrt($i)it is greater than that, sqrt($i)then it will be impossible.

# Think about it again? Forget it.

$arr = [3];

for ($i = 5; $i < 100000; $i += 2) {
    
    

    $sqrt = sqrt($i);

    foreach ($arr as $item) {
    
    
        if ($item <= $sqrt && $i % $item === 0) {
    
    
            continue 2;
        }
    }

    $item += 2;

    for ($j = $item; $j < $i; $j++) {
    
    
        if ($i % $j === 0) {
    
    
            continue 2;
        }
    }

    $arr[] = $i;
}

array_unshift($arr, 2);

After this optimization, compared to the last optimized code, the speed is more than doubled by testing with 10w.
Insert picture description here

There should be room for optimization. If you know, please let me know, thank you very much.

Guess you like

Origin blog.csdn.net/z772532526/article/details/104974581