Números primos dentro de 1000 (números de calidad)

1. ¿Qué es un número primo (número primo)?

Entre los números naturales mayores que 1, no hay otros números naturales excepto el 1 y él mismo. Significa: solo puede ser divisible por 1 y por sí mismo .

Dos ideas para resolver problemas

Doble para bucle, la primera capa crece de 2 a 1000, la segunda capa intenta tomar el resto y hay un divisor, que se considera un número no primo.

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

Este método es fácil de entender y la velocidad es buena. Pero las cosas ciertamente no son tan simples.

Tres, ¿una mejor forma?

Después de todo, todavía no soy bueno con los algoritmos. Quiero ver cómo lo hacen otros, pero Baidu y Google echan un vistazo. La respuesta es básicamente

<?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 />";
}

¡Quien lo escribió! Es muy malo. Uno es necesario para dividir 1 y a sí mismo, y el otro es que la segunda capa se incrementa a su propio tamaño cada vez.

Cuatro, optimización

Piénsalo por ti mismo, aunque no he hecho muchas preguntas, también conozco la programación dinámica, siento vagamente que cada número detrás estará relacionado con el frente.

¡Oh! Si hay un resto después de dividir por 2, no es necesario dividir por 4, y si hay un resto después de dividir por 3, no es necesario dividir por 9, y así sucesivamente. Se pueden utilizar los números primos obtenidos antes. Declare una matriz de números primos, primero verifique si puede ser divisible por los números en la matriz principal. Si ninguno es divisible, la posición inicial del ciclo de segundo nivel para cambia, comenzando desde el número primo anterior después del primer número.

// 如果数组是空的,第一次++$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;
}

Bueno, prueba, no hay problema.

Echemos un vistazo a la velocidad de estos tres métodos (en el orden del método en línea, mi primera edición, después de la optimización), 1000 es demasiado pequeño, cambie a 1W.

Inserte la descripción de la imagen aquí
La diferencia de velocidad entre el primero y el segundo es 9 veces, y el segundo y el tercero son 7 veces la velocidad.

Elimine el primer método y vuelva a probar con 10W.
Inserte la descripción de la imagen aquí
La diferencia de velocidad es 9 veces.

Cinco, volver a optimizar

# ¿Piensas en ello de nuevo? Uno de los números primos es muy especial, es decir 2, es el único número par y el resto son números impares. Entonces, cada vez que puede incrementar en 2 y $i++puede cambiarlo a $i += 2, ya que luego será un número impar, no siempre tiene que intentar dividir por 2 primero.

# ¿Piensas en ello de nuevo? De acuerdo con la idea anterior, el segundo nivel del bucle for ++$itemdebe cambiarse para agregar 2 cada vez. Por supuesto, este es el mismo que el punto anterior de optimización, y el efecto inicial es bastante débil.

# ¿Piensas en ello de nuevo? Bueno, primero imprime estos números primos y encuentra el patrón. . . . . ¡Oye! Divide, para que cada uno atraviese todas las matrices de números primos, ¿qué pasa aquí? Cuando el dividendo atraviesa más de la mitad del número de verificación actual, ¡es imposible ser divisible! Agregar juicio$item < count($arr) / 2

# ¿Piensas en ello de nuevo? Bueno, de acuerdo con la idea anterior, ¿por qué debe ser la mitad y no está permitido 1/3? Si 1/3 puede ser divisible por 3, y así sucesivamente, 1/5, 1/7, 1/11 ... Cuando es la cabeza? Bueno, debería estar enraizado, cuando $i / sqrt($i)sea mayor que eso, sqrt($i)será imposible.

# ¿Piensas en ello de nuevo? Olvídalo.

$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);

Después de esta optimización, en comparación con el último código optimizado, la velocidad es más del doble probando con 10w.
Inserte la descripción de la imagen aquí

Debe haber espacio para la optimización. Si lo sabe, hágamelo saber, muchas gracias.

Supongo que te gusta

Origin blog.csdn.net/z772532526/article/details/104974581
Recomendado
Clasificación