算法零基础学习关于素数的那些事儿
Posted 妙七先生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法零基础学习关于素数的那些事儿相关的知识,希望对你有一定的参考价值。
文章目录
关于素数
素数,又称为质数。它是指那些只包含 1 和 它本身 两个因子的自然数。与之相对应的数称为 合数。
特别的, 1既不是素数也不是合数
用程序判定一个数是否是素数
使用素数的定义
因为素数只有 1 和 它本身 两个因子,所以,我们可以遍历[2,n-1]中的每一个数,如果其中没有 n 的因子,那么就说明 n 是素数。代码如下:
public boolean isPrime(int n)
for (int i = 2; i < n; ++i)
if (n % i == 0)
return false;
return true;
这种做法的时间复杂度为O(n)
。
优化一
我们可以对上面的方法进行优化。
根据素数的定义,我们可以知道,判断一个数是否为素数,最关键的一点在于这个数是否包含除去 1 和 它自身之外 的其他因子。我们的优化从它的因子特征入手:
我们先看两个例子:
6
÷
2
=
3
6\\div2=3
6÷2=3
150
÷
3
=
50
150 \\div 3=50
150÷3=50
我们发现:
- 对于任何一个正整数 n,如果它可以被 x 整除,那么就可以说明,它也可以被 n/x 整除。
- 并且,对于 x 和 n/x,一定有一个较小值。我们假设 x 是较小值,那么一定会存在 x ≤ n / x x \\leq n /x x≤n/x。也就是说, x ≤ n x \\leq \\sqrtn x≤n。
所以,我们不需要遍历[2,n-1]
中的每一个数,只需要遍历在[2,
n
\\sqrtn
n]中是否存在 n 的因子即可。优化后的代码如下:
public boolean isPrime(int n)
int s = (int)Math.sqrt(n);
for (int i = 2; i <= s; ++i)
if (n % i == 0)
return false;
return true;
这里,它的时间复杂度优化到了 O(sqrt(n))
。
推荐题目
题目 |
---|
1492. n的第k个因子 |
1952. 三除数 |
筛选出 n 之内的所有素数
枚举法
这是最简单的方法,就是枚举[1,n]所有的数,判断是否是素数。
public List<Integer> selPrime(int n)
List<Integer> list = new ArrayList<>();
for(int i = 1; i <= n; ++i)
if(isPrime(i))
list.add(i);
return list;
boolean isPrime(int n)
int s = (int)Math.sqrt(n);
for(int i = 2; i <= s; ++i)
if(n % i == 0)
return false;
return true;
时间复杂度:O( n 3 2 n^\\frac32 n23)
埃氏筛
枚举法虽然简单,但是它的性能却并不可观。所以,介绍另外一种方法——埃氏筛。简单介绍一下它:
埃氏筛,全称埃拉托斯特尼筛法,是一种由希腊数学家埃拉托斯特尼所提出的一种简单检定素数的算法。
📖核心思想
在遍历 [1, n] 的过程中,如果发现某个素数 p,那么它的 i 倍一定不是素数。
所以,我们可以使用一个 长度为 n 的数组标识素数。在发现某一个素数之后,将它的所有倍数标识为合数。
👨💻代码
// 0 代表素数,1 代表合数
public int countPrimes(int n)
if(n < 2)
return 0;
int cnt = 0;
int[] primes = new int[n+1];
primes[0] = primes[1] = 1;
for(int i = 2; i <= n; ++i)
if(primes[i] == 0)
++cnt;
for(int j = 2; ; ++j)
if(j * i <= n)
primes[j * i] = 1;
推荐题目
题目 |
---|
204. 计数质数 |
1175.质数排列 |
866. 回文素数 |
筛选N以内的素数 |
以上是关于算法零基础学习关于素数的那些事儿的主要内容,如果未能解决你的问题,请参考以下文章
《从零开始学Swift》学习笔记(Day 11)——数据类型那些事儿?