1000以内的素数(质数)

一、啥是素数(质数)?

在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。 意思就是: 只能被1和它自己整除

二、解题思路

双重for循环,第一层从2增长到1000,第二层尝试取余,出现整除,视为非素数。

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

这种方式很容易理解,速度上也不错。但是事情当然不会这么简单。

三、更好的方法?

毕竟我还是不擅长算法的,想着看看别人怎么做,然而百度和google了一下。答案基本都是

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

谁写的!也太坑了吧。一个是非要除一下1和自己本身,另一个是第二层每次都递增到自身大小。

四、优化

自己想想吧,虽然做过的题不多,但也知道动态规划,隐隐约约觉得每个后边的数字都会和前边有关联。

噢!除以2之后有余数,就不必除4了,除以3有余数就不必除以9了,以此类推。之前得到的素数都可以被利用到。声明一个素数数组,先验证是否可以被素数组里的数整除,如果都无法整除,第二层for循环的起始位置发生更改,从前一个素数之后一个数开始。

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

嗯,测试,没问题。

我们来看一下这三种方法的速度吧(依次是网上的方法,我的第一版,优化后),1000太小了,换成1W。

在这里插入图片描述
第一种和第二种速度差9倍,第二种和第三种,速度差7倍。

去掉第一种方法,用10W再测试。
在这里插入图片描述
速度差了9倍。

五、再优化

# 再想想呢?素数里有一个数很特殊,那就是2,它是唯一一个偶数,其余都是奇数。所以每次可以自增2,$i++可以改成$i += 2,既然之后都是奇数了,也就不必再总是先试一次除以2了。

# 再想想呢?按照上一个想法,第二层for循环,++$item应该改成每次加2。当然,这个和上一点优化一样,起始作用相当微弱。

# 再想想呢? 嗯,先把这些素数打印出来,找规律。。。。。哎!整除,我foreach遍历所有素数数组这里有什么不对,当被除数遍历到超过当前验证数字一半的时候,就不可能被整除了呢!即加上判断$item < count($arr) / 2

# 再想想呢?嗯,,,按照上一个想法,为什么一定是一半呢,1/3 也不可以啊,如果能1/3早就被3整除了,以此类推,1/5、1/7、1/11 … 什么时候是头呢?嗯,应该是开根,当大于$i / sqrt($i)也就是sqrt($i)之后就不可能了。

# 再想想呢?算了。

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

这样优化后,对比上一次优化后的代码,以10w测试,速度提升一倍多。
在这里插入图片描述

应该还有优化的空间,若您知道,烦请告诉我,不胜感谢。

猜你喜欢

转载自blog.csdn.net/z772532526/article/details/104974581