Description:
Count the number of prime numbers less than a non-negative number, n.
思路:这题第一种思路是写一个is_prime函数,来对每一个数验证一次是否是prime。
这个方法在这个题里表现不快,但也是一个学习is_prime函数的机会。
首先,验证一个数是不是prime,只需要用小于它的所有正整数全除一遍看是否能整除就行。实际上,我们只需要试验到sqrt(n),不需要到n-1。因为假如p * q = n的话,p和q是关于sqrt(n)对称的。
再然后,所有数都可以表示成6 * k + i的形式,其中k为整数,i = -1, 0, 1, 2, 3, 4。当i = 0, 2, 4时该数一定是偶数,不可能是prime。当i = 3时,这个数能被3整除,也不是。因此,若一个数是prime,除了2和3,它一定能被表示成 6 * k +/- 1的形式。
由此,我们获得了一个检测n是否是prime的思路:先验证n能否被2或者3整除。然后验证n能否被不大于sqrt(n)的所有能表示成6 * k +/- 1形式的数整除。
1 bool is_prime(int n) 2 { 3 if (n <= 1) return false; 4 else if (n <= 3) return true; 5 else if (n % 2 == 0 || n % 3 == 0) 6 return false; 7 for (int i = 5; i * i <= n; i += 6) 8 if (n % i == 0 || n % (i + 2) == 0) 9 return false; 10 return true; 11 }
接下来介绍这个题里能用到的解法。
思路是我们先使用一个大小为n的数组,然后从2开始,将所有2的倍数全部标记成非prime。然后是3,将所有3的倍数全部标记成非prime。这里要注意的是,因为2 * 3已经在2的倍数那一步标注过了,因此这里从3的3倍开始。到4的时候,因为4已经被标注为非prime了,因此直接跳过。以此类推,将所有i从i倍开始的所有倍数标注为非prime。这个过程一直持续到i等于sqrt(n)。
1 class Solution { 2 public: 3 int countPrimes(int n) { 4 vector<bool> tab(n, true); 5 for (int i = 2; i * i < n; i++) 6 if (tab[i]) 7 for (int j = i; i * j < n; j++) 8 tab[i * j] = false; 9 int res = 0; 10 for (int i = 2; i < n; i++) 11 if (tab[i]) res++; 12 return res; 13 } 14 };