1. 判断一个数是不是素数
解法1:最经典的版本
1 #include <stdio.h>
2 #include <math.h>
3 #include <stdbool.h> //C99 supports bool type
4
5 bool is_prime(int n) {
6 if (n <= 3) return n > 1;
7 int sqrt_n = sqrt(n);
8
9 for (int i = 2; i <= sqrt_n; ++i) {
10 if (n % i == 0) return false;
11 }
12
13 return true;
14 }
15
16 int main()
17 {
18 int n;
19 while(~scanf("%d", &n)) {
20 printf("%d is_prime() = %d\n", n, is_prime(n));
21 }
22 return 0;
23 }
解法2:参考自https://blog.youkuaiyun.com/afei__/article/details/80638460
思路是:质数有一个特点,就是它总是等于 6x-1 或者 6x+1,其中 x 是大于等于1的自然数。
证明:首先 6x 肯定不是质数,因为它能被 6 整除;其次 6x+2 肯定也不是质数,因为它还能被2整除;依次类推,6x+3 肯定能被 3 整除;6x+4 肯定能被 2 整除。那么,就只有 6x+1 和 6x+5 (即等同于6x-1) 可能是质数了。所以循环的步长可以设为 6,然后每次只判断 6 两侧的数即可。也即,我们对n,从5到sqrt(n),挨个判断5,7,11,13,17,19...是不是可以被n整除就可以了。
16 bool is_prime_v2(int n) {
17 if (n <= 3) return n > 1;
18
19 if (n % 6 != 1 && n % 6 != 5) {
20 return false;
21 }
22
23 int sqrt_n = sqrt(n);
24 for (int i = 5; i <= sqrt_n; i += 6) {
25 if (n % i == 0 || n % (i + 2) == 0) {
26 return false;
27 }
28 }
29 return true;
30 }
2. 判断小于n的prime数的数目
LintCode 1324. countPrimes.
解法1:普通筛法
class Solution {
public:
/**
* @param n: a integer
* @return: return a integer
*/
int countPrimes(int n) {
if (n == 1) return 0;
int sqrtn = sqrt(n);
vector<int> filter(n, 1);
for (int i = 2; i <= sqrtn; ++i) {
int j = i << 1;
while (j < n) {
filter[j] = 0;
j += i;
}
}
int count = 0;
for (int i = 1; i <= n; ++i) {
if (filter[i] == 1) {
count++;
}
}
return count - 1; //1 is not prime
}
};
普通筛法的另一个版本:
当n>=46350后会出错,因为n*n>MAX_INT
class Solution {
public:
/**
* @param n: a integer
* @return: return a integer
*/
int countPrimes(int n) {
vector<int> flags(n + 1, 0);
for (int i = 2; i <= n; ++i) {
if (flags[i]) continue;
//fails after i >=46350 as i*i exceeds MAX_INT
for (int j = i * i; j <= n; j += i) {
flags[j] = 1;
}
}
int count = 0;
for (int i = 2; i < n; ++i) {
if (!flags[i]) count++;
}
return count; //1 is not prime
}
};
解法2:线性筛。。时间复杂度O(n)。
关于线性筛法的介绍见 https://zhuanlan.zhihu.com/p/42609585
class Solution {
public:
/**
* @param n: a integer
* @return: return a integer
*/
int countPrimes(int n) {
vector<int> primes(n + 1, 0); //primes[i]: 0 => unprocessed, -1 => non-prime, >0 => a prime-number
int count = 0;
for (int i = 2; i < n; ++i) {
if (!primes[i]) {
primes[count++] = i;
}
for (int j = 0; j < count; ++j) {
int product = primes[j] * i;
if (product > n) break;
primes[product] = -1; //just show it is not prime-number. It can be any number except 0.
if (i % primes[j] == 0) break;
}
}
return count;
}
};
3. 质因数分解
LintCode 1295: Given a positive integer N, you need to factorize all integers between (1, N]. Then you have to count the number of the total prime numbers.
解法1: DP,时间复杂度是O(n * sqrt(n))。
class Solution {
public:
/**
* @param N: a number
* @return: the number of prime numbers.
*/
int Count_PrimeNum(int N) {
int result = 0;
vector<int> records(N + 1, 1);
records[0] = 0, records[1] = 0;
for (int i = 2; i <= N; ++i) {
result += records[i];
int count = N / i;
for (int j = 1; j <= count; ++j) {
records[i * j] = records[i] + records[j];
}
}
return result;
}
};
解法2:基于Pollard_Rho算法,注意Pollard_Rho算法时间复杂度O(n^ 1/4),所以总的时间复杂度是O(n^ 5/4)。
class Solution {
public:
/**
* @param N: a number
* @return: the number of prime numbers.
*/
int Count_PrimeNum(int N) {
int result = 0;
vector<int> nums(N + 1, -1);
for (int i = 2; i <= N; ++i) {
result += Pollard_Rho(i);
}
return result;
}
private:
int Pollard_Rho(int n) {
int count = 0;
//vector<int> result;
int sqrtn = sqrt(n);
for (int i = 2; i <= sqrtn;) {
while (n % i == 0) {
count++;
// result.push_back(i);
n /= i;
}
if (i == 2) i += 1;
else i += 2;
}
// if (count == 0) count = 1; // if n is non-2 prime
if (n > 1) count++;
return count;
}
};
4. 丑数类题目
这类题目都是说有n个素数,然后让你求第k个丑数。算法就是给每个素数一个指针,然后n个指针挨个挨个试,看哪个素数的倍数最小。
LeetCode 313. Super Ugly Number
Write a program to find the nth
super ugly number.
Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes
of size k
.
Example:
Input: n = 12,primes
=[2,7,13,19]
Output: 32 Explanation:[1,2,4,7,8,13,14,16,19,26,28,32]
is the sequence of the first 12 super ugly numbers givenprimes
=[2,7,13,19]
of size 4.
Note:
1
is a super ugly number for any givenprimes
.- The given numbers in
primes
are in ascending order. - 0 <
k
≤ 100, 0 <n
≤ 106, 0 <primes[i]
< 1000. - The nth super ugly number is guaranteed to fit in a 32-bit signed integer.
class Solution {
public:
int nthSuperUglyNumber(int n, vector<int>& primes) {
int num = primes.size();
vector<int> indexes(num, 1);
vector<int> uglys(n + 1);
uglys[1] = 1;
for (int i = 2; i <= n; ++i) {
int candidate = uglys[indexes[0]] * primes[0];
// int candidate_index = 0;
for (int j = 1; j < num; ++j) {
int temp = uglys[indexes[j]] * primes[j];
if (candidate > temp) {
candidate = temp;
//candidate_index = j;
}
}
for (int j = 0; j < num; ++j) {
if (candidate == (uglys[indexes[j]] * primes[j])) {
indexes[j]++;
}
}
uglys[i] = candidate;
}
return uglys[n];
}
};