算法题解----分解质因数 + 筛质数的三种算法

第一部分 : 分解质因数

任何一个大于 1 的正整数都可以写成这样的形式:

  

其中 Pi 是 一个质数

那么我们可以用怎么样的算法去得到 这个正整数的 质因数以及其 指数呢?

我们可以用 试除法这个方法:
① 找到N的一个 质约数 然后让N一只除这个质约数,直到 N % Pi != 0 

② 记录我们除这个质约数除了多少次 那么次数就是这个质约数的指数

这里还有几点要注意:

我们循环控制变量i 是这样循环的 for( i = 2 ; i <= n/i ; i++)

这样就可以找到N的绝大部分质因数 不过有可能我们会漏掉一个质因数

比如说当N很大的时候 他可能有一个质因数是大于 sqrt(N) 的

所以我们最后要进行一个判断 if( N>1 ) 那么最后N就是原来N的最后一个最大的质因数 而且这个质因数的指数一定是1

 

话不多说,上代码~

 

 

int cnt,primes[N];                            //存储质因数
int s[N];                                     //存储指数    

void divide(int n)
{
    for(int i = 2 ; i <= n / i ; i ++)
    {
         if(n % i == 0)
         {   
               primes[cnt++] = i;
               while( n%i == 0 )
             {
                 s[cnt]++;
                 n /= i;
             }
    }
    
      if(n>1)
     {
         primes[cnt] = n;
         s[cnt] = 1; 
     }
}    

 

 

 

 第二部分:筛质数

学过编程的同学一定都写过筛质数的程序吧

很经典的一道题 : 筛取1000以内的质数

里面有一种比较好的算法:

 

bool is_prime(int n)
{
    for(int i=2 ; i<=n/i;i++)
    {
          if(n % i ==0)
          {
                return false;
           } 
    }
    return true;
}    

 

这就是试除法筛素数的算法,那么为什么我们要设置 i <= n/i 而不是 i <= n-1 呢 ?

因为我们这个算法是用来判断这个数是不是素数,如果这个数是合数那个它一定可以写成 a * b 且 a !=1 b != 1的形式 这是完全对称的,所以只用判断i到 sqrt(n)就可以了 。这个算法的时间复杂度为O(n logn)

那么对于筛素数我们有没有更高效的算法呢?

这里我就介绍两种筛素数的算法: 埃氏筛和线性筛

首先介绍埃氏筛

 

我们还要用一个st数组来存储每个数的状态,如果这个数被筛掉了就把这个st设置为true

话不多说 上代码

int cnt,primes[N];
bool st[N];
void get_primes(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!st[i])                    //如果i是质数
        {
             primes[cnt++] = i;
             for(int j = i ; j <=n ;j+=i) st[j]=true;   //筛去i的倍数
         }
    }  

}

 

埃氏筛的算法时间复杂度为O(n loglogn) 是十分接近O(n)的时间复杂度的, 也是算法竞赛常用的筛质数的算法

为什么埃氏筛的时间复杂度不是O(n)的呢?

因为 如果用埃氏筛的算法 一个数可能要被筛掉很多次 。

我再来介绍一个更好的算法去筛质数:线性筛,从名字来看就知道线性筛的时间复杂度是O(n)的,那么线性筛是如何筛掉合数的呢?

其实线性筛的本质也是筛掉质数的倍数,不过它中间的过程和埃氏筛有点不同

埃氏筛是只要是质数是当前合数的质因子就筛

而线性筛思路是这样的,如果质因数是当前数的最小质因子,那么这个质因数也一定是这个质因数乘以当前数的最小质因子,那么就可以筛掉

避免了一个数被重复筛去的情况,好,那么代码是如何写的呢?

void get_primes(int n)
{
     for(int i=2 ;i<=n;i++)
     {
         if(!st[i]) primes[cnt++] = i;
         for(int j = 0; primes[j] <= n/i;j++)
         {
               st[primes[j] * i] = true;
               if(i % primes[j] == 0) break;
          }     
     }    
}

 

posted @ 2021-08-21 00:33  Apak陈柏宇  阅读(276)  评论(0编辑  收藏  举报