第四期POWER8大赛(计算质数)

这是一个实现计算素数的问题。但由于这 个问题本身的特殊性(输出某范围内所有素数),我给出一个方案,或许和大家的一样。

bool数组A:A[i]=True表示 2*i+1 为素数。如果要找10亿以内的素数,就要申请一个5亿bit的bool数组A,占用空间略小于100M,这种小范围的情况还是可用的。A全部初始化为TRUE;

解法就很简单,按照下面的步骤来做就行了:

1.首先把A[0]=FALSE,赋值。

1.从A[0]开始,如果A[i]==TRUE,则进行以下步骤:

a) 求出A[i]所代表的数字x = 2*i+1;把x的x倍到n倍(nx<=10亿)的数字在bool数组A中所指示的A[i]赋值为FALSE,(如果本来为TRUE)。

b)做完后继续下一个A[i]

以上过程完成后A数组就记录了除2以外的所有素数了。下面把他们读出来:

a)输出2;

b)从A[0]开始如果A[i]==TRUE;输出2*i+1;


这个算法非常简单,复杂度远远低于O(nlog(n));按照我的理解时间复杂度应该已经较低了。这个方法的基本思想是排除法。和大家的方法相比,不知道是不是英雄所见略同啊!

至于复杂度的估算这里给个提示:每一个A[i]被访问的次数等于这个A[i]的指示的数分解因子后,不同因子的个数,比如如果2*i+1=3*3*7*13*23那么A[i]会被访问4次,并尝试赋值A[i]为FALSE。


和大家讨论之后,得到启发,发现可以实现一个线性算法,如下:

这是一个质数算法和前一个有很多相同的地方,一些基本的假设这里继续申明一遍:

假设要找1-M范围内的所有质数

布尔数组A[M+1],A[i]=TRUE表示有 i是质数;全赋值为TRUE,A[0],A[1]赋值为0;

质数队列B(足够长可以顺序存下所有质数);len_B=1,,len_B[0]=2;

1.        从i=3开始;如果A[i]==TRUE则将i存入B数组中,len_B++。

2.        按照以下方法找到i并的置换为FALSE:

a)        从B的素数集合中取len_B次,取出的len_B个质数的乘积所指示的位置赋值为FALSE;遍历穷尽所有取法组合(同一个质数可以取多次,比如3放入B后,会对2*2=4,2*3=6,3*3=9进行置换)【怎么遍历才能最方便的取遍所有组合?】

3.        对下一个A[i]进行同上的操作;

这种做法的正确性我就不多说了。至于复杂度方面:每个数的标记最多只会被翻转一次,因为它只有一种因子分解的方法。如果遍历组合的时候没有无效计算(简单一点就是你编程的时候没有类似于if的判断),那就必定是线性时间了。

 

遍历所有组合的时候怎样才能避开无效计算呢?及怎么在 2*3*2 和2*2*3、3*2*2这些中只找到一个并且一次呢,其实我们只要加上一个限制就是取数组计算乘积时加上一个限制后取的质数大于或等与先取的质数(因为数组B是升序的,所以这里也不用进行比较),就可以保证不需要进行无效计算了。

说到这里,这个求质数的方法已经从理论可行了,当然实现可能还是另一回事,毕竟有些问题在开发的时候才会突显出来。


你可能感兴趣的:(题集)