LeetCode 第 204 题 (Count Primes)

LeetCode 第 204 题 (Count Primes)

Description:
Count the number of prime numbers less than a non-negative number, n.

计算小于 N 的素数的个数。这道题目比较简单。但是想提高计算效率与需要费点脑筋。

判断一个数字 n 是不是素数的简单方法是 用 n 去除 2,3,4,,n1 ,如果都不能整除就说明这个数是素数。
按照这个思路可以写个简单的函数。

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

这个代码还可以优化一点。不用除到 n1 ,只要除到 [n] 就可以了。

bool isPrime(int n)
{
    if(n < 1) return false;
    for (int i = 2; i * i < n; i++) 
    {
          if (num % i == 0) 
          {
              return false;
          }
    }
    return true;
}

这个代码每次判断时都要算一遍 ii ,而第 69 题给出了一个计算 [n] 的快速算法,利用这个算法还可以再优化一点。

 int mySqrt(int x)
{
    if(x <= 0) return 0;
    int a1 = 1;
    int a2 = 46341 * 2 - 1;
    unsigned int a, y;
    if(a2 > x / 2) a2 = x;
    do
    {
        a = (a1 + a2) / 2;
        y = a * a;
        if(y == x) return a;
        if(y > x)
        {
            a2 = a;
        }
        else
        {
            a1 = a;
        }
    }while(a1 + 1 < a2);
    a = (a1 + a2) / 2;
    return a;
}
 bool isPrime(int n)
{
    if(n < 1) return false;
    int sn = mySqrt(n);
    for (int i = 2; i <= sn; i++) 
    {
          if (num % i == 0) 
          {
              return false;
          }
    }
    return true;
}

之后计算素数个数的代码就可以写成这样。

int countPrimes(int n) 
{
   int count = 0;
   for (int i = 1; i < n; i++) 
   {
      if (isPrime(i)) count++;
   }
   return count;
}

即使写成这样,这个代码的计算复杂度还是有点大,isPrime 函数的时间复杂度是 O(n) ,countPrimes 函数的时间复杂度是 O(n) ,所以整体的复杂度是 O(nn)

实际上有一种简单的算法,时间复杂度可以降低到 O(nlog(log(n))) 。这种方法就是所谓的 Eratosthenes 筛选法(Sieve of Eratosthenes)。首先建立一张有 n 个元素的大表,表中每个元素都标记为 1。那么这个表中 2 是第一个素数,2 的倍数都不是素数,那么把表中 2 的倍数都标记为 0。之后找表中在 2 后面第一个元素值为 1 的元素,这个元素就是第二个素数,当然这个数是 3 ,然后再将表中3 的倍数全部标记为 0 。重复这个过程,就可以将表中所有的素数找出来了。按照这个思路写的代码如下:

int countPrimes(int n)
{
    bool *primeTable = new bool[n];

    for (int i = 0; i < n; i++)
    {
        primeTable[i] = true;
    }

    int i = 2;
    int count = 0;
    while (i * i < n)
    {
        if (primeTable[i])
        {
            count++;
            for (int j = i * i; j < n; j += i)
            {
                primeTable[j] = false;
            }
        }
        i++;
    }
    while (i < n)
    {
        if(primeTable[i])
        {
            count++;
        }
        i++;
    }
    delete[] primeTable;
    return count;
}

除此之外,还有更快的判段一个数是否是素数的方法,时间复杂度为 O(1)。不过那种算法属于概率算法,有一定的小概率出错,以后有时间单独写一篇博客介绍那些方法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值