数字的魅力之情有独钟的素数

情有独钟的素数

什么是素数

素数(Prime number)也称为质数,是指在非0自然数中,除了1与其本身之外不拥有其他因数的自然数。也就是说,素数需要满足两个条件:

  • 大于1的整数;
  • 只拥有1和其自身两个因数。

例子1

本文章的任务就是输出100以内的所有素数,如2、3、5、7、11、13…
先理清一下思路:
(1)需要有一个2~100的外循环,还要有一个小于当前数的因子内循环;
(2)需要有一个判断是否可整除的i语句(整除就是余数为0)。
求100以内的素数的思路如下图所示。
在这里插入图片描述

代码实现

实现代码如下:
Python

# 100以内的素数算法
prime = []
#从2开始遍厉到100
for i in range (2,101) :
    flag =1 #i是否力素数的标记
    # 因数应该是大于1小于自身的数
    for j in range (2, i):
        if i%j ==0: #一旦取模(余数)为0
            flag = 0 # 更改标记为0
            break   # 直接跳出本循环
    if flag == 1: # 标记为 1,则为素数
        prime.append(i) # 添加到 prime 列表
print("100以内的素数:",prime)

Java

 List<Integer> arr = new ArrayList<>();
            int flag ;
            for(int i=2;i<101;i++){
   
                flag =1;
                for (int j=2;j<i;j++){
   
                    if(i%j==0){
   
                        flag =0;
                        break;
                    }
                }
                if(flag==1){
   
                    arr.add(i);
                }
            }
            System.out.println(arr);

输出结果如下:

在这里插入图片描述

例子2 “优化素数计算:从暴力求解到开方优化”

只要解决了问题就结束了吗?这可不是学习的态度。《诗经》有云:“如切如磋,如琢如磨。”其斯之谓与?我们可要精益求精啊。这段代码虽实现了我们的任务,但它的时间复杂度太大,100 以内的素数还可以,如果是1000或10000呢?
可是要怎样使时间复杂度变小呢?只有两个地方可以下手——要么是外循环,要么是内循环。我们知道:任意数若等于两个非0自然数的乘积,则这两个因子中至少有一个小于该数的二分之一。
当然,我们还可以再缩小一下范围,把“二分之一”缩减为“开方”,这样就大大缩减了内循环的运行时间。思路如下图所示。
在这里插入图片描述

代码实现

实现代码如下:
Python

# -*- coding: utf-8 -*-
import math

#100以内的素数算法二
prime = []
#从2开始遍历到 100
for i in range (2,101) :
    #因数应该是大于1小于自身的开方+1
    for j in range(2,int(math.sqrt(i))+1):
        #一旦取模(余数)为0
        if i%j == 0:
            break   #直接跳出本循环
    # 若余数均不0,则为素数
    else:
        prime.append(i) # 添加到 prime 列表中

print("100以内的全部素数:",prime)

Java

 	List<Integer> arr = new ArrayList<>();
            int j;
            for(int i=2;i<101;i++){
   
                for (j=2;j<(int)Math.sqrt(i)+1;j++){
   
                    if(i%j==0){
   
                        break;
                    }
                }
                if(j==(int)Math.sqrt(i)+1){
   
                    arr.add(i);
                }
            }
            System.out.println(arr);

注意:例子二的内循环范围记得加1,否则输出结果错误

输出结果如下:

在这里插入图片描述

看,我们只改了一个值,便大大缩短了算法的运行时间,这就是思维逻辑的重要性。只要逻辑捋顺了,代码实现就很容易了。

例子3

观察结果发现,5+1=6,7-1=6,11+1=12,13-1=12, 17+1=18,19-1=18,23+1=24…这些都是6的倍数,那我们当不是可以利用(6n-1)和(6n+1)两个公式便可以得到质数的排列了?那么下一个质数必该是6×4+1=35,再下个质数就是6×5-1=29,但是25并不是质数,因此排列的规律还需要我们一步步地分析。
我们先不看2和3,从5开始往后数,所有的素数都分布在6n(n≥1)左右两侧,即(6n-1)与(6n+1)。那以6为间距的其他数又是如何分布的呢?6n %6=0,(6n+2)%2=0,(6n+3)%3=0,(6n+4)%2=0,(6n+5)则又回到了(6n-1),一个循环结束了。
我们发现:除去2和3以外,所有的素数都是符合(6n-1)和(6n+1)规律的,但符合这两个公式的数字不一定就是素数,因此这是一个充分非必要条件,而不是充要条件。
据此,我们可以进一步缩小因子范围,思路如下图所示。
在这里插入图片描述

代码实现

实现代码如下:
Python

# -*- coding: utf-8 -*-
import math

# 100 以内的素数算法三
prime = []
prime. extend([2, 3]) #已知2和3 是素数
# 从5开始遍历到 100
for i in range (5,101) :
    # 非素数时
    if i % 2 == 0 or i%3 ==0 :
        continue # 跳过后续操作,直接进入下一循环
    # 因数应该是大于1小于自身的开方+2,以6为单位
    for j in range(6, int(math.sqrt(i))+2,6):
        # 当可以整除6 的倍数时两侧的数字也为非素数
        if i%(j-1) == 0 or i%(j+1) ==0:
            break # 直接跳出本循环
    # 若余数均不为O,则为素数
    else:
        prime.append(i)
# 添加到 prime 列表中
print("100以内的全部素数:",prime)

Java

List<Integer> arr = new ArrayList<>();
            arr.add(2);
            arr.add(3);
            int j;
            for(int i=5;i<101;i++){
   
                if (i%2==0 || i%3==0)
                    continue;
                for (j=6;j<(int)Math.sqrt(i)+2;j+=6){
   
                    if(i%(j-1)==0 || i%(j+1)==0){
   
                        break;
                    }
                }
                if(j>=(int)Math.sqrt(i)+2){
   
                    arr.add(i);
                }
            }
            System.out.println(arr);

注意:continue 和 break 非常好用,不熟悉它们的用法的读者请务必掌握。

输出结果如下:

在这里插入图片描述

“素数的广泛应用与未解决的数学难题”

这么一看果然“顺眼”多了,虽然思路让人不好理解,但多看几遍还是能理解的。一般来说,实现相同功能的不同代码,越简洁的就越晦涩,运行时间越少的也越难懂。当然,素数的检测算法远不止于此,还有费马素性测试(Fermat primality test)、米勒-拉宾素性测试 (Miller-Rabin primality test)、Solovay-Strassen 测试、卢卡斯-菜默素性测试 (Lucas-Lehmer primality test)和埃拉托斯特尼筛法等。素数在自然数中的分布极其复架,其被广泛应用到密码学中,即在公钥中插入素数并进行编码,以此达到提高破译难度的目的。
同时,素数领域还存在许多数学家们一直无法解决的难题,最著名的莫过于“哥德巴赫猜想”和“黎曼猜想”。哥德巴赫和黎曼在数学界都是举足轻重的人物。哥德巴赫猜想是:“是否每个大于2的偶数都可写成两个素数之和?”娶曼猜想是:“素数出现的频率与黎曼 ζ \zeta ζ函数紧密相关。”这两个猜想虽然未能被完全验证,但已经被广泛应用,黎曼猜想甚至已经成为当今数学文献中一千多条数学命题的前提。

相关推荐

  1. 简单数学问题素数判断及获取

    2024-02-16 08:08:01       30 阅读
  2. 判断素数方法

    2024-02-16 08:08:01       7 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-16 08:08:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-16 08:08:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-16 08:08:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-16 08:08:01       20 阅读

热门阅读

  1. 【动态规划初识】整数划分

    2024-02-16 08:08:01       32 阅读
  2. 【数据统计】A股分红率排行榜2023

    2024-02-16 08:08:01       94 阅读
  3. 企业微信自动推送机器人的应用与价值

    2024-02-16 08:08:01       36 阅读
  4. GoRules:Go的业务规则引擎

    2024-02-16 08:08:01       35 阅读
  5. Educational Codeforces Round 161 (Rated for Div. 2)(A - E)

    2024-02-16 08:08:01       32 阅读
  6. 学习Spring的第十八天

    2024-02-16 08:08:01       36 阅读
  7. leetcode - 2149. Rearrange Array Elements by Sign

    2024-02-16 08:08:01       30 阅读