首页 > 其他分享 >质数判断——暴力方法、埃氏筛与线性筛

质数判断——暴力方法、埃氏筛与线性筛

时间:2023-01-02 19:55:24浏览次数:40  
标签:埃氏 标记 质数 boolean 复杂度 线性 合数

质数判断

  问题背景为:我们希望判断前n个数是否为质数,即得到isPrime[n+1](此处沿用java语言定义)数组。

暴力方法

  传统意义上的对质数的判断方法,是依据质数的定义——质数不能被大于1小于自身的数整除。所以本质上就是对所有小于它的数进行遍历整除,如果存在能够整除的则说明不是质数,否则为质数。很明显时间复杂度为O(n)
  基于此方法,我们可以进行一定的优化,如根据定理:合数一定有一个因子小于\(\sqrt{n}\),来使遍历范围由[2, n-1]转为[2, floor(\(\sqrt{n-1}\))],时间复杂度为O(\(\sqrt{n}\))。

private static boolean[] getPrimeArray__ByRude(int toNum) {
      boolean[] isPrime = new boolean[toNum+1];
      for (int i = 2;i <= toNum;i++) {
          isPrime[i] = true;
      }

      for (int i = 2;i <= toNum;i++) {
          int sqrt = (int) Math.floor(Math.sqrt(i));
          for (int j = 2;j <= sqrt;j++) {
              if (i % j == 0) {
                  isPrime[i] = false;
                  break;
              }
          }
      }
      return isPrime;
  }

  很明显,上述算法时间复杂度为O(n\(\sqrt{n}\))。

埃氏筛

  暴力方法只是将单个数是否为质数得判断方法对区间内所有数进行使用,没有考虑到数与数相互之间的联系,所以无论如何对传统方法优化都无法在时间复杂度上进行进一步突破。
  现在考虑:对于一个质数p,当我们把它当作因子时,对任意的i>=2,i*p一定是合数。
  因此,我们可以通过上述思想从2到n找到所有的合数,进而也就是找到了所有的质数。
  其中有一个可以优化的点:对于质数p,事实上我们只需要考虑i>=p部分,也就是i作为i*p的因子;这是因为对于i小于p的情况,i(或者i的因子)已作为i*p的因子来标记了i*p是合数。

private static boolean[] getPrimeArray__ByEratosthenesSieve(int toNum) {
      boolean[] isPrime = new boolean[toNum+1];
      for (int i = 2;i <= toNum;i++) {
          isPrime[i] = true;
      }

      for (int i = 2;i <= toNum;i++) {
          if (isPrime[i]) {
              for (int j = i*i; j <= toNum;j+=i) {
                  isPrime[j] = false;
              }
          }
      }
      return isPrime;
  }

  不加证明的,时间复杂度为O(nloglogn)。

线性筛

  对于埃氏筛,虽然没有证明时间复杂度,但是我们思考为什么其时间复杂度中会多出loglogn这部分。
  埃氏筛事实上是通过对所有合数进行标记的方式进行判断的,理论上如果所有合数仅标记一次,那么时间复杂度应该为O(n)。但事实上多出一部分,是因为有些合数被多次标记。例如:45被3和5同时标记
  所以线性筛的核心目的就是避免多次标记
  与埃氏筛不同,线性筛通过一个primes数组记录了从小到大出现的质数,并且对于从2开始的数i,将i与所有此时已经记录在primes中的质数相乘,并将其标记为合数。事实上,所对于i,如果在遍历到它之前没有被标记为合数,那么将其视为素数。
  线性筛的核心点在于:如果i可以被一个primes中的p整除,即i%p==0,那么对于所以之后的p都不再考虑(注意,与p的乘积需要标记合数)。这是因为此后的合数i*p会i/p*p_标记(p_为p的下一个质数),这保证了所有合数被其最小质因数标记。

boolean[] isPrime = new boolean[toNum+1];
      ArrayList<Integer> primes = new ArrayList<>();
      for (int i = 2;i <= toNum;i++) {
          isPrime[i] = true;
      }

      for (int i = 2;i <= toNum;i++) {
          if (isPrime[i]) {
              primes.add(i);
          }
          for (int j = 0; j <= primes.size() && primes.get(j) * i <= toNum;j+=1) {
              isPrime[primes.get(j) * i] = false;
              if (i % primes.get(j) == 0) {
                  break;
              }
          }
      }
      return isPrime;

  由于每个合数仅被标记一遍,所以时间复杂度为O(n)。

标签:埃氏,标记,质数,boolean,复杂度,线性,合数
From: https://www.cnblogs.com/learningIsSoHard/p/17020367.html

相关文章

  • 线性表之链式存储
    目录初始化一个空线性表空链式表的抽象表达查找按序号按值在位序i前插入一个新元素X删除指定位序i的元素返回线性表L的长度n吐槽初始化一个空线性表空链式表的抽象表达/......
  • C. Koxia and Number Theory (线性同余)https://codeforces.com/contest/1770/problem/C
    https://codeforces.com/contest/1770/attachments/download/18470/editorial.pdf这个pdf都写得很明白了,这个c题终于懂了,麻了à$a_i^j\leqb^j$本来只需要枚举n/2之内的......
  • [第326场周赛]分解质因数,埃氏筛,欧拉筛
    leetcode新年福利,本次周赛没有Hard难度的题目,然后我就第一次AK了~总的来说不是很难,涉及到了三个算法,在此记录一下。分解质因数题目链接:​​6279.数组乘积中的不同质因数数......
  • 【新生寒训】day 5 线性dp
    【新生寒训】day5线性dp学习:https://zhuanlan.zhihu.com/p/121032448https://zhuanlan.zhihu.com/p/311598413题单:https://vjudge.csgrandeur.cn/contest/533002ht......
  • 关于常系数齐次线性递推数列能被表示成等比数列线性和的证明
    退役OIer来诈尸了,祝大家新年快乐。问题引入下面的所有数列默认下标从\(0\)开始。对于一个数列\(\{a_n\}\),如果其满足\(k\)阶常系数齐次线性递推关系:\[a_n=\sum_{......
  • 【机器学习】--线性回归中L1正则和L2正则
    =========================================================声明:由于不同平台阅读格式不一致(尤其源码部分),所以获取更多阅读体验!!个人网站地址:​​http://www.lhworldblog.......
  • 【机械】板的线性和非线性弯曲分析附MATLAB 代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 线性方程组的直接解法——Gauss消去法
    考虑线性方程组\[\mathrm{A}x=\mathrm{b}\]其中,\(\mathrm{A}=(a_{ij})_{n\timesn}\),\(\mathrm{b}=[b_1,b_2,\cdots,b_n]^{\mathrm{T}}\)。在线性代数的课程中,我们已经学......
  • 线性规划 2
    强对偶性的证明接续上次的讨论,我们已经得到了弱对偶性,这导出了最大匹配不大于最小点覆盖。然而需要了解的是,在二分图中二者相等,这就对应着强对偶性。我们首先需要考察的......
  • 线性表
    1.定义和分类1.线性表是具有相同数据类型n个数据元素的有限序列,n为表长,其表示为:L=(a1,a2,a3,...,an),是最基本,最常见的一种数据结构2.前驱元素和后驱元素:若A元素在......