写在前面的话
- 基于Python 3.7
- 基础数学(小学5年级内容),正好儿子上到这个阶段就写一下
- 涉及部分python语法
题目
- 相关的题目可以是判断一个数是否是质数
- 取出0~N之间的质数等等
质数特性
- 在大于1的自然数中,除了1和它本身以外不再有其他因数
- 唯一的偶质数是2
- 0和1都不是质数
思路1
将一个数从2除到N-1遇到能整除的就不是素数,反之就是。
def prime_list(n):
dest_list=[]
for i in range(2,n+1):
for j in range(2,i):
if i%j==0:
break
else:
dest_list.append(i)
return dest_list
print(prime_list(100))
for else
上述代码中有一段是for else,这个基础语法一般提的不多,但的确有用。我们来看两个例子。
for i in [1,2,3]:
if i%2==0:
break
else:
print(i)
else:
print('hello')
# i=1 打印
# i=2 break
# else没有打印
输出:1
for i in [1,2,3]:
if i%4==0:
break
else:
print(i)
else:
print('hello')
# i=1,2,3均print,for循环做完了
# else执行了
输出: 1 2 3 hello
总结:如果for正常结束,就执行else),若中途遇到break),就不执行else
思路2
我们方法一的思路,时间复杂度好像是O(n²),2层循环,虽然会break,但效率还是很低的。100000以内的求解竟然要38.6s,100w我的电脑都要运行好久。
这个时候我们要看下质数的理论了。 其实我们发现我们求解质数的时候,根本不需要从2除到N-1,当除数大于商的时候我们就不用计算了。
以13为例: 13÷2=6--1 13÷3=4-1 13÷4=3-1 #到这里我们不用算了 13÷5=2-3 13÷6=2-1
用数学的话来说我们只需除到平方根就好了。
import math
def prime_list(n):
dest_list=[]
for i in range(2,n+1):
for j in range(2,int(math.sqrt(i))+1):
if i%j==0:
break
else:
dest_list.append(i)
return dest_list
print(prime_list(100))
我们来看下时间,我们发现同样的代码,节省了大量时间,10w数据之用了276ms,可以测试100w花了5s。1000w数据测试约耗时2分半。
思路3
那是否还能提高更多呢?可以的! 还是要用到素数相关的理论:对于大于3的质数,只分布在6x-1和6x+1两数列中(x为非0自然数)。即都在6的倍数的两侧。
def prime_list(n):
list1=[]
for i in range(2,n+1):
if i == 2 or i == 3 or i == 5:
list1.append(i)
else:
if i % 6 == 1 or i % 6 ==5:
for j in range(2,int(math.sqrt(i)+1)):
if i%j ==0:
break
else:
list1.append(i)
return list1
print(prime_list(1000000))
质数相关的理论
哥德巴赫猜想:任何大于5的奇数都是三个素数之和 -衍生:任何一个大于2的偶数都是两个素数之和 伯特兰猜想:对于任意正整数n>1,存在一个素数p,使得n<p<2n 孪生素数猜想:存在无穷多的形如p和p+2的素数对 n2+1 猜想:存在无穷多个形如n2+1的素数,其中n是正整数