素数和问题
又名 寻找素数对
问题描述
Description
Given an even number ( greater than 2 ), return two prime numbers whose sum will be equal to given number. There are several combinations possible. Print only first such pair.
NOTE: A solution will always exist, read Goldbach’s conjecture.Also, solve the problem in linear time complexity, i.e., O(n).
Input
The first line contains T, the number of test cases. The following T lines consist of a number each, for which we’ll find two prime numbers.Note: The number would always be an even number.
Output
For every test case print two prime numbers space separated, such that the smaller number appears first. Answer for each test case must be in a new line.
Sample Input 1
5
74
1024
66
8
9990
Sample Output 1
3 71
3 1021
5 61
3 5
17 9973
题目解析
哥德巴赫猜想: 任意取出一个偶数(>2),来寻找两个素数,使得其和等于该偶数.
由于可以有不同的素数对来表示同一个偶数,输出素数对中第一个素数最小的那对
思路解析
- 创建一个数组,存放范围内的数
- 先判断给定范围内的数哪些是素数哪些不是,并更新数组
- 判断(i,n-i)是否同时为素数,有则返回结果
代码实现(python)
解法1
传统求质数方式,时间复杂度O(n√n)
# Generate all prime numbers less than n.
def SieveOfEratosthenes(n, isPrime):
# Initialize all entries of boolean
# array as True. A value in isPrime[i]
# will finally be False if i is Not a
# prime, else True bool isPrime[n+1]
isPrime[0] = isPrime[1] = False
for i in range(2, n + 1):
isPrime[i] = True
p = 2
while (p * p <= n):
# If isPrime[p] is not changed,
# then it is a prime
if (isPrime[p] == True):
# Update all multiples of p
i = p * p
while (i <= n):
isPrime[i] = False
i += p
p += 1
# Prints a prime pair with given sum
def findPrimePair(n):
# Generating primes using Sieve
isPrime = [0] * (n + 1)
SieveOfEratosthenes(n, isPrime)
# Traversing all numbers to find
# first pair
for i in range(0, n):
if (isPrime[i] and isPrime[n - i]):
print(i, (n - i))
return
if __name__ == '__main__':
case_num = int(input().strip())
for i in range(case_num):
N = int(input().strip())
findPrimePair(N)
# This code is contributed by
# Smitha Dinesh Semwal
解法2
使用埃筛选法求质数,时间复杂度O(n log log n) 接近于 O(n)
# 埃式筛选法
def no_of_primes(n):
no_list = [1] * (n + 1)
no_list[0] = 0
no_list[1] = 0
for i in range(2, n + 1):
if no_list[i] == 1:
for j in range(2 * i, n + 1, i):
no_list[j] = 0
return no_list
if __name__ == '__main__':
t = int(input().strip())
for i in range(t):
n = int(input())
no_list = no_of_primes(n)
for i in range(0, n):
if no_list[i] == 1 and no_list[n - i] == 1:
print(i, (n - i))
break
解法3
使用欧式筛法求质数,时间复杂度 O(n)
欧式筛法博客
原理:,每个数都可以拆成一个最小的质因数(素数)和一个最大的合数,当遍历到那个最大的合数的时候,就依据最小的质因数将其筛选出去,这样每个数只被他最小的质因数筛选出去了一次,因此时间复杂度可以达到O(N)。
算法而核心就在于这句
if a % b == 0: break
如何理解?
筛选原则: 保证每个数都被其最小质因数(素数)筛去
设i=a b=prime
若 i % prime == 0,则有i = prime * b
则用prime_next去约去 i * prime_next时候有 i * prime_next = prime * b * prime_next
此时prime 小于 prime_next,如果用prime_next约去则不满足条件
因此当遍历到b*(prime_next)时i * prime_next一定可以被prime约去,因此现在就不用约
举个例子:
设i =6 ,prime =2 prime_next =3
若 6 * 2 ==0 ,则有6 = 2 * 3
则用3去约去 6 * 3 =18时候,有 6 * 3 = 2 * 3 * 3
此时2 <3 如果用3约去则不满足条件
因此当遍历到3 * 3 = 9 时, 18一定可以被2约去,因此现在就不用约去18
(本图来自https://www.cnblogs.com/grubbyskyer/p/3852421.html )
def no_of_primes2(n):
no_list = [1] * (n + 1)
no_list[0] = 0
no_list[1] = 0
prime = []
for a in range(2, n + 1):
if no_list[a] == 1:
prime.append(a)
for b in prime:
if a * b > n: break
no_list[a * b] = 0
if a % b == 0: break
return no_list