
소수는 1과 자기 자신만으로 나누어 떨어지는 양의 정수이다. 즉, 소수의 약수는 1과 자기 자신만 존재한다.
예를 들어,
첫 번째 방법은 2부터 n-1까지 확인하는 방법이다.
소수의 정의에 따르면 정수 n이 소수이기 위해서는 n을 2부터 n-1까지 순서대로 나누었을 때, 나누어 떨어지는 수가 있어서는 안 된다. 즉, n을 2부터 n-1까지 순서대로 나누었을 때, 나머지가 0이 되는 수가 있어서는 안 된다.
const isPrime = (n) => {
for (let i = 2; i < n; i++) {
if (num % i === 0) return false;
}
return true;
};
이러한 방식을 이용하면 시간 복잡도는 O(n) 이다.
두 번째 방법은 2부터 n/2까지만 확인하는 방법이다. n의 약수는 자신의 절반을 넘을 수 없다.
예를 들어, n이 16이라면 n/2인 8보다 큰 수로 나누었을 땐, 자기 자신 16을 제외하고는 나누어 떨어지는 경우가 없다. 즉, n/2를 초과하는 수로 나누면 나머지가 0이 되는 수가 나올 수 없다.
const isPrime = (n) => {
for (let i = 2; i < n / 2; i++) {
if (num % i === 0) return false;
}
return true;
};
이러한 방식을 이용하면 최대 n/2번 조회하지만, 시간 복잡도는 상수를 제외하므로 시간 복잡도는 O(n) 이다.
세 번째 방법은 2부터 √n까지만 확인하는 방법이다.
이는 약수의 대칭성을 이용한 방법이다. 약수는 짝으로 존재한다. 따라서 쌍을 이루는 약수 중 한 쪽만 찾으면 나머지 한 쪽은 확인하지 않아도 된다.
예를 들어, n이 20이라면 n의 약수 쌍은 1 * 20 , 2 * 10 , 4 * 5 이다. √20 = 4.xxx 이므로 4까지만 검사해도 약수의 대칭성에 의해 5, 10, 20은 20의 약수인 것이 보장되기 때문에 확인하지 않아도 된다.
const isPrime = (n) => {
for (let i = 2; i < Math.sqrt(n); i++) {
if (num % i === 0) return false;
}
return true;
};
Math.sqrt() 메서드는 숫자의 제곱근을 반환한다. 만약 n이 음수면 NaN 을 반환한다.이러한 방식을 이용하면 시간 복잡도는 O(√n) 이다.
네 번째 방법은 에라코스테네스의 체를 활용하는 방법이다.
에라토스테네스의 체는 고대 그리스 수학자 에라토스테네스가 발견한 소수를 찾는 방법이다.

위 그림의 경우, 11^2 > 120이므로 11보다 작은 수의 배수들만 지워도 충분하다. 즉, 120보다 작거나 같은 수 가운데 2, 3, 4, 5의 배수를 지우고 남는 수는 모두 소수이다.
결국, 2부터 n의 제곱근까지 반복하며 해당 수의 배수를 지우고 남는 수를 구하는 것이다.
const solution = (n) => {
// 인덱스가 0부터 n까지인 배열 생성 (인덱스 0과 1은 false, 나머지는 true)
let arr = Array(n + 1).fill(true).fill(false, 0, 2);
// i는 2부터 n의 제곱근까지만 반복
for (let i = 2; i * i <= n; i++) {
if (arr[i]) {
// i의 배수는 false로 변경
for (let j = i * i; j <= n; j += i) {
arr[j] = false;
}
}
}
// 0부터 n까지의 숫자 중 소수만 true인 배열 반환
return arr;
};
let isPrime = solution(100);
// 소수의 개수 구하기
let count = isPrimes.filter(e => e).length; // 25
// 소수 반환하기
let primes = isPrimes.map((v, i) => (v) ? i : 0).filter(e => e);
// [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
참조