C++面试宝典第5题:判断素数

题目

        判断一个正整数是否为素数有哪几种方法,每种方法的时间复杂度怎么样。

解析

        素数又称质数,是指在大于1的自然数中,除了1和它本身以外,不再有其他因数的自然数。素数只有1和它本身两个正因数,最小的素数是2,素数的个数是无穷的。

        埃拉托斯特尼筛法(Sieve of Eratosthenes),简称“筛法”,是一种简单判定素数的算法,也是一种历史悠久的筛法。要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。其方法是,给出要筛数值的范围n,先用2去筛,把2留下,把2的倍数剔除掉;再用下一个素数,也就是3筛,把3留下,把3的倍数剔除掉;不断重复下去。

        根据上面的思路,我们给出了下面的示例代码。

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

bool IsPrime3(unsigned int uiNum)
{
    if (uiNum <= 1)
    {
        return false;
    }

    vector<bool> vctPrime(uiNum + 1, true);
    vctPrime[0] = false;
    vctPrime[1] = false;
    unsigned int uiTemp = (unsigned int)sqrt(uiNum);
    for (unsigned int i = 2; i <= uiTemp; i++)
    {
        if (vctPrime[i])
        {
            for (unsigned int j = i * i; j <= uiNum; j += i)
            {
                vctPrime[j] = false;
                if (j == uiNum)
                {
                    break;
                }
            }
        }
    }

    return vctPrime[uiNum];
}

int main()
{
    for (unsigned int i = 0; i < 100; i++)
    {
        if (IsPrime3(i))
        {
            cout << i << " ";
        }
    }

    return 0;
}

        通过上面的代码可以得知,埃拉托斯特尼筛法的时间复杂度为O(nlogn)。

        判断一个数是否为素数,最直接也最常用的方法为:循环遍历从2到该数的平方根之间的所有整数,尝试能否整除该数。如果存在能整除该数的整数,则该数不是素数;否则,该数是素数。这种方法的时间复杂度为O(sqrt(n)),具体实现,可参考下面的示例代码。

#include <iostream>
#include <cmath>
#include <Windows.h>
using namespace std;

bool IsPrime1(unsigned int uiNum)
{
    if (uiNum <= 1)
    {
        return false;
    }

    unsigned int uiTemp = (unsigned int)sqrt(uiNum);
    for (unsigned int i = 2; i <= uiTemp; i++)
    {
        if (uiNum % i == 0)
        {
            return false;
        }
    }

    return true;
}

int main()
{
    unsigned int uiTick = GetTickCount();
    for (unsigned int i = 0; i < 10000000; i++)
    {
        IsPrime1(i);
    }

    // 输出:2719ms
    cout << GetTickCount() - uiTick << "ms" << endl;
    return 0;
}

        还有一种更高效的方法,需要用到素数分布的规律。该规律为:大于等于5的素数,一定和6的倍数相邻。比如:素数5、7在6的两侧,素数11、13在12的两侧,素数17、19在18的两侧。

        该分布规律的证明其实并不难,假设有一个数x>=1,则可将大于等于5的自然数N表示为:6x-1、6x、6x+1、6x+2、6x+3、6x+4、6x+5、6(x+1)、6(x+1)+1、...。可以看到,不在6的倍数两侧的数为:6x+2、6x+3、6x+4。由于6x+2为2(3x+1),6x+3为3(2x+1),6x+4为2(3x+2),故它们一定不是素数。再除去6x本身,则素数只可能出现在6x的相邻两侧。但是注意,在6x的相邻两侧,并不一定就是素数。

        对于N为6x-1、6x+1这两种情况,可以将其表示为:6i-1、6i、6i+1、6i+2、6i+3、6i+4。如果N能被6i、6i+2、6i+4整除,则N至少得是一个偶数,但6x-1、6x+1明显为一个奇数,故不成立。如果N能被6i+3整除,则N至少能被3整除,但6x-1、6x+1不可能被3整除,故亦不成立。综上,只需要考虑6i-1和6i+1的情况,即:循环的步长可以设置为6,每次判断循环变量k和k+2的情况。理论上,该方法的时间复杂度为O(sqrt(n)/3)。

        根据上面的思路,我们给出了下面的示例代码。

#include <iostream>
#include <cmath>
#include <Windows.h>
using namespace std;

bool IsPrime2(unsigned int uiNum)
{
    // 单独处理0和1
    if (uiNum <= 1)
    {
        return false;
    }

    // 单独处理2和3
    if (uiNum == 2 || uiNum == 3)
    {
        return true;
    }

    // 不在6的倍数两侧的,一定不是素数
    if (uiNum % 6 != 1 && uiNum % 6 != 5)
    {
        return false;
    }

    // 在6的倍数两侧的,也可能不是素数
    unsigned int uiTemp = (unsigned int)sqrt(uiNum);
    for (unsigned int i = 5; i <= uiTemp; i += 6)
    {
        // 只需要考虑6i-1和6i+1的情况
        if (uiNum % i == 0 || uiNum % (i + 2) == 0)
        {
            return false;
        }
    }
        
    // 排除所有情况,剩余的肯定是素数
    return 1 ;
}

int main()
{
    unsigned int uiTick = GetTickCount();
    for (unsigned int i = 0; i < 10000000; i++)
    {
        IsPrime2(i);
    }

    // 输出:1015ms
    cout << GetTickCount() - uiTick << "ms" << endl;
    return 0;
}

总结

        通过这道题,我们学习了判断一个正整数是否为素数的若干方法。既有历史悠久的埃拉托斯特尼筛法,也有常用的遍历法。在遍历法的基础上,我们利用素数的分布规律,对算法进行了优化,提升了其运行效率,降低了其时间复杂度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/240096.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Vue】router.push用法实现路由跳转

目录 router.push用法 在Login.vue中 在Register.vue中 ​ 上一篇&#xff1a;登录与注册界面的制作 https://blog.csdn.net/m0_67930426/article/details/134895214?spm1001.2014.3001.5502 制作了登录与注册界面&#xff0c;并介绍了相关表单元素即属性的用法 在登录页面…

第三十四周:文献阅读+LSTM学习

目录 摘要 Abstract 文献阅读&#xff1a;综合EMD-LSTM模型在城市排水管网水质预测中的应用 现有问题 提出方法 EMD-LSTM综合模型 研究框架 结论 Long Short-term Memory(长短期记忆) 1. LSTM的结构 2. Multiple-layer LSTM 3.3 LSTM Example 3. GRU LSTM实现PM2…

【K8S 系列】认识k8s、k8s架构

一、什么是k8s? Kubernetes 简称 k8s&#xff0c;是支持云原生部署的一个平台&#xff0c;k8s 本质上就是用来简化微服务的开发和部署的&#xff0c;用于自动化部署、扩展和管理容器化应用的开源容器编排技术。对于传统的docker其实也提供了容器编排的技术docker-compose&…

Rust语言GUI库之gtk安装

文章目录 工具链安装管理软件vcpkgvcpkg介绍安装vcpkg 安装gtk遇到的问题Rust其他依赖package-confg 工具链安装管理软件vcpkg vcpkg介绍 在使用C/C编写项目时, 引用第三方库是很麻烦的事, 需要手动下载源码然后编译最后再添加到项目里&#xff0c;配置头文件、lib、dll&…

PyTorch: 基于【MobileNet V2】处理MNIST数据集的图像分类任务【准确率99%+】

目录 引言1. 安装PyTorch2. 下载并加载MNIST数据集3. 搭建基于MobileNet V2的图像分类模型运行结果&#xff08;重点看网络开头和结束位置即可&#xff09; 4. 设置超参数、损失函数、优化器5. 训练模型6. 测试模型运行结果 完整代码结束语 引言 在深度学习和计算机视觉的世界…

Windows使用selenium操作浏览器爬虫

以前的大部分程序都是操作Chrome&#xff0c;很少有操作Edge&#xff0c;现在以Edge为例。 Selenium本身是无法直接控制浏览器的&#xff0c;不同的浏览器需要不同的驱动程序&#xff0c;Google Chrome需要安装ChromeDriver、Edge需要安装Microsoft Edge WebDriver&#xff0c…

【PostgreSQL】从零开始:(一)初识PostgreSQL

从零开始:&#xff08;一&#xff09;初识PostgreSQL PostgreSQL数据库介绍为什么使用 PostgreSQL&#xff1f;那么多最终用户,云厂商为什么要贡献核心代码&#xff1f;基于PostgreSQL底层开发的好处&#xff1a;为什么要学习PostgreSQL&#xff1f;截止本文发布之日&#xff0…

Web安全之XXE漏洞原理及实践学习

一、原理&#xff1a; XXE漏洞全称即XML外部实体注入漏洞。 攻击者强制XML解析器去访问攻击者指定的资源内容(可能是系统上本地文件亦或是远程系统上的文件)&#xff0c;导致可加载恶意外部文件&#xff0c;利用file协议造成文件读取、命令执行、内网端口扫描、攻击内网网站等…

【图论-匈牙利算法】Hungary Algorithm完整代码(一) 之 matlab实现

学习参考链接 博客 分配问题与匈牙利算法 带你入门多目标跟踪&#xff08;三&#xff09;匈牙利算法&KM算法 视频 运筹学 | 例题详解指派问题 前言 图论-匈牙利算法原理参见上述参考连接中的博客与BiliBili博主的学习视屏&#xff0c;讲的很好很透彻。强烈建议看完&#…

自定义日志打印功能--C++

一、介绍 日志是计算机程序中用于记录运行时事件和状态的重要工具。通过记录关键信息和错误情况&#xff0c;日志可以帮助程序开发人员和维护人员追踪程序的执行过程&#xff0c;排查问题和改进性能。 在软件开发中&#xff0c;日志通常记录如下类型的信息&#xff1a; 事件信…

关于碰撞试验

主要参数&#xff1a; 冲击与碰撞试验的主要参数及调整方法 - 百度文库 碰撞试验的技术指标包括&#xff1a;峰值加速度、脉冲持续时间、速度变化量&#xff08;半正弦波&#xff09;、每方向碰撞次数。 加速度&#xff1a;冲击的强度&#xff0c;单位为g&#xff1b;一般为3…

Zygote 进程启动过程

首语 在Android系统中&#xff0c;DVM(Dalvik虚拟机)和ART、应用程序进程以及运行系统的关键服务的SystemServer进程都是由Zygote进程创建的&#xff0c;也可以将其称之为孵化器&#xff0c;它通过fork(复制进程)的形式来创建应用程序进程和SystemServer进程。 Zygote进程是在…

记录一次chatGPT人机协同实战辅助科研——根据词库自动进行情感分析

有一个Excel中的一列&#xff0c;读取文本判断文本包含积极情感词.txt和消极情感词.txt的个数&#xff0c;分别生成两列统计数据 请将 ‘your_file.xlsx’ 替换为你的Excel文件名&#xff0c;Your Text Column’替换为包含文本的列名。 这个程序首先读取了积极和消极情感词&…

(第68天)DBCA 克隆 PDB

介绍 在前面课程我们讲过使用 DBCA 创建数据库以及搭建 DataGuard 等功能,在多租户这章节,要讲下如何使用 DBCA 克隆 PDB。 18C 开始支持使用 DBCA 在本地 CDB 中克隆 PDB19C 升级支持使用 DBCA 克隆 PDB 到远端 CDB 中19C 升级支持使用 DBCA 重定向迁移 PDB 到远端 CDB 中本…

2023/12/12作业

思维导图 作业&#xff1a; 成果图 代码 #include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { speechernew QTextToSpeech(this); ui->setupUi(this); //一直获取当前时间 idst…

海思越影系列3516DV500/3519DV500/3519AV200/SD3403平台的AI一体化工业相机设计思路

随着工业自动化的发展&#xff0c;生产线对机器视觉的数量要求越来越多&#xff0c;由于数量的增加&#xff0c;视觉系统占的空间也越来越大&#xff0c;给生产线的布局带来困扰。 另一方面随着视觉SOC的发展&#xff0c;越来越多的视觉SOC都逐渐带有一定的算力&#xff0c;一体…

AI全栈大模型工程师(二十八)如何做好算法备案

互联网信息服务算法 什么情况下要备案&#xff1f; 对于B2B业务&#xff0c;不需要备案。 但在B2C领域&#xff0c;一切要视具体情况而定。 如果我们自主训练大型模型&#xff0c;这是必要的。 但如果是基于第三方模型提供的服务&#xff0c;建议选择那些已获得备案并且具有较大…

DevOps - Spug 自动化运维平台

关于Spug 官网&#xff1a;https://spug.cc/ Spug&#xff1a;麻雀&#xff0c;麻雀虽小&#xff0c;五脏俱全。 Spug是面向中小型企业设计的轻量级无Agent的自动化运维平台&#xff0c;整合了主机管理、主机批量执行、主机在线终端、文件在线上传下载、应用发布部署、在线任…

[Angular] 笔记1:开发设置 , 双向绑定

1 设置开发环境 1.1 安装 node 下载 node&#xff0c;因为要使用 npm 工具&#xff0c;教程中使用 Angualr 14, 最新版 node 20 用不了&#xff0c;安装 node 16 就可以。 1.2 安装 Angular CLI Angular CLI 是用于创建 Angular 工程的工具集&#xff0c;使用如下命令&…

redis的深度理解

上篇博客我们说到了redis的基本概念和基本操作&#xff0c;本篇我们就更深入去了解一些redis的操作和概念&#xff0c;我们就从red的主从同步、redis哨兵模式和redis集群三个方面来了解redis数据库 一、主从同步 像MySQL一样&#xff0c;redis是支持主从同步的&#xff0c;而…