【线性求质数】【最小质因数】浅析欧拉筛
欧拉筛
【算法简介】
由于每个大于等于2的合数必定存在一个最小的质因数,所以只要筛去每个质数的倍数就相当于筛去了所有合数。但欧拉筛相比埃氏筛最大的优化就在于欧拉筛保证每个合数只被筛了一次,且是被其最小的质因数筛去的,所以欧拉筛的时间复杂度可以达到O(N)。
而如何保证每个合数都只被最小质因数筛去呢?让我们先来看一看欧拉筛的实现(第一次用python写博客,代码习惯不太好请见谅):
1 n = input() 2 Del = [0] * (n + 1) 3 prime = [] 4 for a in range(2,n + 1): 5 if Del[a] == 0: 6 prime.append(a) 7 for b in prime: 8 if a * b > n: break 9 Del[a * b] = 1 10 if a % b == 0: break 11 print prime
算法其他部分和埃氏筛思路类似,在此就不再赘述。而核心就在于这句
if a % b == 0: break
当a % b == 0时,b为a的一个质因子,所以a = K * b。令K = a / b,则用质数数组的接下来某个质数b'去筛a * b'的时候,a * b' == K * b * b',因而b和b'都是a * b'的质因子。由于b < b',故a * b'的最小质因数是b而不是b'。如果不break就会用非最小质因数b'筛完之后,再当a' == K * b'时用b又筛一遍,提高了复杂度。所以当a % b == 0时,后续的a * b'只需让循环中接下来的某一个a' == (a / b) * b'时用b筛掉即可,既保证了每个数都被其最小质因数筛去,也保证了每个数都只被筛一次。
【利用欧拉筛求最小质因数】
根据【算法简介】中的介绍,每个非质数都被其最小质因数筛去,所以只要在被筛去的时候记录一下被哪个质数筛去,这样就的到了最小质因数,相当于是欧拉筛的“副产品”。python实现如下:
n = input("") Del = [0] * (n + 1) Son = [0] * (n + 1) prime = [] for a in range(2,n + 1): if Del[a] == 0: prime.append(a) Son[a] = a for b in prime: if a * b > n: break Del[a * b] = 1 Son[a * b] = b if a % b == 0: break print prime; for a in range(2,n + 1): print a,"->",Son[a];