LeetCode 第 204 题 (Count Primes)
Description:
Count the number of prime numbers less than a non-negative number, n.
计算小于 N 的素数的个数。这道题目比较简单。但是想提高计算效率与需要费点脑筋。
判断一个数字
n
是不是素数的简单方法是 用
按照这个思路可以写个简单的函数。
bool isPrime(int n)
{
if(n < 1) return false;
for (int i = 2; i < n; i++)
{
if (num % i == 0)
{
return false;
}
}
return true;
}
这个代码还可以优化一点。不用除到 n−1 ,只要除到 [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;
}
这个代码每次判断时都要算一遍 i∗i ,而第 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
个元素的大表,表中每个元素都标记为
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;
}
除此之外,还有更快的判段一个数是否是素数的方法,时间复杂度为