经典算法题之(三)------ 判断和寻找素数

 

判断和寻找素数问题:

 

判断一个数是否为素数:

① 定义法(brute force):除了1和本身不能被其他数整除

遍历2到n-1,如果有任何可以被整除的数就返回false

 

② 升级版,任何一个数如果可以表示为两个数的乘积:n = m1 * m2,则必然有m1或m2小于或等于\sqrt{n}(不可能都大于\sqrt{n},不然矛盾),这样将①法的验证的右边界从n-1减小到\sqrt{n}

 

③ 再进阶,剔除了[2,\sqrt{n}]之间的偶数,再验证。

        考虑到这样一个事实,如果一个数不能被2整除,则必然也不能被2,6...等任何2的倍数(偶数)整除,所以可以“预处理”一下:剔除[2,\sqrt{n}]之间的偶数再验证。

 

④ 如何继续进阶?

        有了③的思想,很容易衍生开来:剔除3的倍数,4由于是2的倍数已经剔除了,过;剔除5的倍数,6过,7的倍数,8过,9过,10过,11的倍数......很容易得出一个结论,如果可能的话,尽量剔除从2开始到\sqrt{n}之间的素数的倍数,然后再进行验证。

       一个显而易见的结论是,很明显,当剔除到\sqrt{n}时,[2,\sqrt{n}]之间全部都是素数,这时只需要用这个素数集合去整除n即可验证。即如果有条件的话,验证一个数是否为素数可以用[2,\sqrt{n}]之间的素数集去测试。

      

这样引出两个问题:

1)如果没有条件,即不知道[2,\sqrt{n}]之间素数集的先验知识,怎么尽量快速地验证[2,\sqrt{n}]之间的因子?

      先看这样一个看似和本问题毫不相关的结论:任何一个自然数都可以表示为6k-1,6k,6k+1,6k+2,6k+3或6k+4中的一个

     可以看做自变量为k,因变量为{6k-1,6k,6k+1,6k+2,6k+3,6k+4},在二维坐标系上表现为(k,Y)的点集。当k=0时,表现为(0,0),(0,1),(0,2),(0,3),(0,4) 5个点,k=1时,为(1,5),(1,6),(1,7),(1,8),(1,9),(1,10)6个点......显而易见,点集可以覆盖所有的y正数值(6(k+1)-1 = 6k +4 +1)刚好衔接上)

      现在来考察6k-1,6k,6k+1,6k+2,6k+3或6k+4哪些可能为素6k,6k+2,6k+4为2的倍数,不可能,6k和6k+3为3的倍数,不可能,所以只有6k-1或6k+1可能为素数。

  所以可以这么说,素数集为集合{k∈N| y= 2,3,6k-1或6k+1}的子集。

 

      现在,回到原来的问题:不知道[2,\sqrt{n}]之间素数集的先验知识,怎么尽量快速地验证[2,\sqrt{n}]之间的因子?

       利用红字的结论,可以这么做:筛选时,验证2,3,6k-1或6k+1是否能整除n即可,其中6k+1 <= \sqrt{n}

       

      回顾一下这个方法:在未知[2,\sqrt{n}]之间素数集的条件下,采用这样一种相对高效的方式,验证[2,\sqrt{n}]中的一部分(2/6 = 33.33%)是否能整除n,也请打消这样的顾虑:为什么不剔除2和3的倍数了?

      回到证明过程,6k-1,6k,6k+1,6k+2,6k+3,6k+4代表了全部自然数,6个一份,其中6k,6k+2,6k+4为2的倍数,6k和6k+3为3的倍数,所以只检验6k-1或6k+1本身就代表筛掉了2和3的倍数,也只筛掉了2和3的倍数。。。

       注意最后一句话,只筛掉了2和3的倍数,这样做比单独筛掉2,3的倍数的好处是:少筛一次公共倍数:6k

       总体而言,筛掉2倍数(6k,6k+2,6k+4)加快50%,单独筛掉2和3的倍数加快5/6 - 1/6 - 1/6 ≈ 50%,第一个1/6是已经被2筛掉的6k,并没有加快,第二个1/6是再次判断6k是否被筛的开销(赔了夫人还折兵),虽然仅仅判断肯定要比筛掉(判断+置标志位)的花销小(<1/6),但是总体带来的收益太小。反观用6k+1,6k-1筛,效率直接上66.66%。划算。

 

现在再考虑一个问题:

2)如果没有条件,即不知道[2,\sqrt{n}]之间素数集的先验知识,怎么尽量快速地验证[2,\sqrt{n}]之间的因子?

 

3)没有条件,用2)中提出的方法创造条件:求出[2,\sqrt{n}]的素数集,再去验证n是否为素数,和1)的方法哪个更好? 再者,如果现在

① 随机给一个自然数(完全随机),

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值