Description:
Count the number of prime numbers less than a non-negative number, n.
Credits:
Special thanks to for adding this problem and creating all test cases.Hint:
-
Let's start with a isPrime function. To determine if a number is prime, we need to check if it is not divisible by any number less than n. The runtime complexity of isPrime function would be O(n) and hence counting the total prime numbers up to n would be O(n2). Could we do better?
返回0~n的所有的质数个数;写了几个代码都time exceeded了简单的思想很简单,就是要过时间。看了一个大神的代码。
本题要求我们求出小于n的数中共有多少个质数。相信大部分同学在刚开始学习C语言的时候估计都写过判断一个数为质数的程序。一般的思路为:
bool isPrime(int num) { int s = sqrt(num) + 1; for( int i = 3; i != s; ++i) { if (num mode i == 0) return false; } return true;}
但是若对小于n的每一个数进行上述计算,会重复很多次,效率很低。
这里LeetCode给出了两个提示链接:
第一个链接给出了本题答案的近似估计公式,第二个介绍了一种很好的算法。这里介绍一下第二种思路,想了解得更全面的同学,请猛戳上面的第二个链接。
- 我们知道2是最小的质数,那么2的倍数均不为质数(因为它们可以分解为一个数*2),所以我们可以将小于n的数中2的倍数,全部排除掉。
- 排除掉2的整数倍后,剩下的数中大于2的最小的数就是下一个质数,也就是3.
- 同样我们可以排除掉小于n的数中3的整数倍的数,得到下一个质数为5.
根据上述思路处理,直到获得所有的质数为止。
这里还可以进行一个优化,即对于质数 p,排除掉p的整数倍后,剩下的元素中满足 p<k<p∗p的元素k均为质数。这里简单证明一下:
- 每个非质数均可以分解为若干个(>2,否则k本身为质数)质数的乘积: k=p1∗p2∗⋯∗pm;
- 对于满足p<k<p∗p的元素来说,如果k不为质数,则k可以分解为k=p1∗p2∗⋯∗pm,其中必然有一个质数满足 pi<p;
- 这里用反证法证明。若k=p1∗p2∗⋯∗pm中每一个质数均pi>p;则有k>p∗p,超出限定的条件p<k<p∗p,所以该非质数已经在前面的处理过程中排除掉了。
参考下图可以更容易了解(这里盗一下的图~~)
代码
本题使用动态数组表示小于n的每个元素是否为质数,效率比较高,下面的代码时间为50+ms, 我试过用vector时间一下子到了800+ms,太可怕了。
class Solution {public: int countPrimes(int n) { if (n <= 2) return 0; bool *p = new bool[n]; memset(p, true, sizeof(bool) * n); for (int i = 2; i * i < n; i++) { if (p[i]) { for (int j = 2; j * i < n; j++) p[i * j] = false; } } int cnt = 0; for (int i = 2; i != n; i++) if (p[i]) cnt++; delete[] p; return cnt; }};