首页 找质数
文章
取消

找质数

问题

找出正整数 n 以内的所有质数。

质数,也叫素数,即除了1和自身外无法被其它数整除的大于1的数,如7,只能被1和7整除。质数在算法问题中很常见。

解法

暴力查找法

假设一个数不是质数,则能把它整除的数一定在 \([2,\sqrt{n}]\) 这个较小的范围之内。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import math

def get_primes(n):
    if n < 2:
        return
    yield 2
    for i in range(3, n):
        is_prime = True
        for j in range(2, int(math.sqrt(i)) + 1):
            if i % j == 0:
                is_prime = False

        if is_prime:
            yield i

if __name__ == '__main__':
    primes = [x for x in get_primes(20)]
    # 输出 [2, 3, 5, 7, 11, 13, 17, 19]
    print(primes)

非2,3,5,7的倍数

假设一个数不是质数,则它一定是 2,3,5,7 中的至少一个的倍数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def get_primes(n):
    f = lambda x: x % 2 != 0 and x % 3 != 0 and x % 5 != 0 and x % 7 != 0
    if n < 2:
        return
    for i in range(2, n + 1):
        if i in (2, 3, 5, 7):
            yield i
        else:
            if f(i):
                yield i

if __name__ == '__main__':
    primes = [x for x in get_primes(20)]
    # 输出 [2, 3, 5, 7, 11, 13, 17, 19]
    print(primes)

使用容器标记

此方法本质上还是用到了上面的思想,一个质数不能是 2,3,5,7 的倍数,用一个容器标记 n 以内的各个数是否是质数。标记为质数的元素的索引即是质数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def get_primes(n):
    boxes = [True] * n
    boxes[0] = False  # 0 和 1 不是质数
    boxes[1] = False

    for i in (2, 3, 5, 7):
        # 最小质数的倍数标记为不是质数
        pointer = i * 2
        while pointer < n:
            boxes[pointer] = False
            pointer += i

    return [idx for idx, value in enumerate(boxes) if value]


if __name__ == '__main__':
    primes = get_primes(20)
    print(primes)

上面的过程释义如下,用 √ 标记质数:

初始化, 0 和 1 不是质数:

0123456789
  
10111213141516171819

2 的倍数不是质数:

0123456789
     
10111213141516171819
     

3的倍数不是质数:

0123456789
      
10111213141516171819
    

5的倍数不是质数:

0123456789
      
10111213141516171819
     

7的倍数不是质数:

0123456789
      
10111213141516171819
      

剩下的 2,3,5,7,11,13,17,19 即为质数。

本文由作者按照 CC BY 4.0 进行授权