Check Prime Number
소수는 1보다 큰 정수로, 약수가 1과 자기 자신뿐입니다. 양의 정수 n이 주어집니다. n이 소수이면 true를 반환하고, 그렇지 않으면 false를 반환하세요. 숫자 1은 소수가 아닙니다.
함수
- ninteger
- 테스트할 양의 정수
- 반환값boolean
- n이 소수이면 true, 그렇지 않으면 false
제약 조건
1 ≤ n ≤ 231 - 1
예제
- 입력
- n = 29
- 출력
- true
- 설명
2,3,4,5중 어느 것도29를 나누지 않으며,6 × 6 = 36은 이미29를 넘었으므로 더 이상 찾을 약수가 없습니다.29는 소수입니다.
- 입력
- n = 1
- 출력
- false
- 설명
- 소수는 약수가 정확히 두 개이며,
1과 자기 자신입니다.1은 약수가 하나뿐이므로 답은false입니다.
- 입력
- n = 91
- 출력
- false
- 설명
91은 소수처럼 보이지만,7 × 13 = 91입니다. 나눗셈 인수7은 탐색이√91 ≈ 9.5를 지나기 전에 나타납니다.
제출 시 숨은 테스트 +15개
후속 질문
3보다 큰 모든 소수는 6k-1 또는 6k+1 형태입니다. 이를 이용해 후보 약수의 3분의 1만 테스트할 수 있을까요?
힌트
하나씩 열어 보세요. 열 때마다 조금 더 알려 줍니다.
소수는
2와n-1사이에 약수가 없습니다. 정말 그 전체 범위를 검사해야 할까요?d가n을 나누면n / d도 나누며, 둘 중 하나는√n이하입니다.d * d가n을 넘으면 멈춰도 됩니다.먼저
n < 2와2를 제외한 짝수를 제외하세요. 그런 다음d * d ≤ n인 동안3부터 홀수 약수를 검사하고,d * d는 64비트 타입으로 유지하세요.
풀이
정의에 따르면 2부터 n-1까지의 모든 약수가 아닌지 확인해야 하며, 가장 큰 소수 입력의 경우 나눗셈이 20억 번을 넘습니다. 약수는 곱해서 n이 되는 쌍으로 나타나며, 각 쌍에서 더 작은 수는 √n 이하입니다. 따라서 √n까지만 탐색하면 되며, 홀수 후보는 최대 약 23,000개입니다.
모든 약수를 시도해 보세요
정답이지만 가장 큰 테스트에서는 끝나지 않음
핵심 아이디어
정의가 알고리즘을 알려 줍니다. n ≥ 2인 수는 2, 3, ..., n-1 중 어느 것도 그 수를 나누지 않을 때 소수입니다. 각 후보 d에 대해 n % d == 0인지 검사하고, 나누어떨어지는 첫 번째 후보에서 false를 반환합니다. 91의 경우 반복문은 2부터 6까지 시도한 뒤 7에서 멈춥니다.
먼저 n < 2인 경우를 처리하세요. n = 1이면 후보 범위가 비어 있으므로, 반복문은 약수를 찾지 못하고 1을 소수라고 판단하게 됩니다.
합성수는 보통 일찍 멈추지만, 소수는 모든 검사를 통과하므로 반복문은 끝까지 실행됩니다. 소수인 n = 2147483647의 경우 약 2.1 × 10^9번의 나눗셈을 수행해야 하며, 이는 몇 초 안에 허용되는 횟수를 훨씬 넘습니다.
알고리즘
n < 2이면false를 반환합니다.d를2부터n-1까지 반복합니다.n % d == 0이면false를 반환합니다.- 반복문이 끝난 후
true를 반환합니다.
def isPrime(n):
if n < 2:
return False
for d in range(2, n):
if n % d == 0:
return False
return True제곱근까지의 시행 나눗셈
핵심 아이디어
약수는 쌍으로 나타납니다. d가 n을 나누면 n / d도 나누며, 두 수를 곱하면 n이 됩니다. 두 수가 모두 √n보다 클 수는 없습니다. 그러면 곱이 n보다 커지기 때문입니다. 따라서 n에 1과 자기 자신 이외의 약수가 있다면, 그중 하나는 √n 이하입니다. 91의 경우 약수 쌍은 7과 13이고, 7 ≤ 9.5입니다. √n 이하의 수 중 n을 나누는 수가 없다면 그보다 큰 수 중에도 없습니다.
제곱근 함수를 호출하는 대신 상한을 d * d ≤ n으로 표현하세요. 이렇게 하면 반올림 없이 정수로 계산됩니다. 등호도 중요합니다. 49 = 7 × 7이고, 유일한 약수 7은 정확히 √49에 있습니다.
후보의 절반을 건너뛸 수도 있습니다. 2는 별도로 처리하세요. 짝수 n은 2일 때만 소수입니다. 그 후 홀수 n에는 홀수 약수만 있으므로 3에서 시작해 2씩 증가하면 됩니다. n = 2147483647의 경우 이제 반복문은 2.1 × 10^9번이 아니라 약 23,000번 실행됩니다.
알고리즘
n < 2이면false를 반환합니다.n이 짝수이면n == 2인지 여부를 반환합니다.d를3으로 시작하고,d에 64비트 유형을 사용하여d * d ≤ n인 동안 반복합니다.n % d == 0이면false를 반환합니다. 그렇지 않으면d에2를 더합니다.- 반복문이 끝난 후
true를 반환합니다.
def isPrime(n):
if n < 2:
return False
if n % 2 == 0:
return n == 2 # 2 is the only even prime
d = 3
while d * d <= n:
if n % d == 0:
return False
d += 2
return True
함정과 경계 사례
핵심 아이디어는 한 줄이면 충분합니다. 버그는 경계값, 즉 가장 작은 입력과 마지막 약수에서 발생합니다.
1에 대해true를 반환하는 경우. 약수가 두 개가 아니라 하나이므로 소수가 아닙니다.2가 짝수라는 이유로 제외하는 경우. 짝수를 제외하기 전에n == 2인지 확인하세요.≤대신d * d < n인 동안 반복하는 경우. 그러면9,49,2147117569 = 46337²와 같은 소수의 제곱이 소수로 판정됩니다.d * d에서 오버플로가 발생하는 경우. 32비트int에서는46341 × 46341 = 2147488281을 저장할 수 없어 음수로 돌아가므로 검사가 계속 통과하고 반복문은√n을 훨씬 넘어 계속 실행됩니다.d에 64비트 타입을 사용하거나, 대신d ≤ n / d를 비교하세요.- 부동소수점
sqrt에서 상한을 구한 뒤 소수 부분을 버리는 경우. 여기서double은 모든n을 정확하게 표현하지만, 64비트 입력에서는 반올림으로 인해 실제 제곱근보다 1 작은 값이 나와 중요한 약수 하나를 건너뛸 수 있습니다.d * d ≤ n에는 이런 위험이 없습니다.
자주 묻는 질문4
숫자가 소수인지 확인하는 시간 복잡도는 얼마인가요?
√n까지의 시험 나눗셈은 O(√n) 시간과 O(1) 공간이 걸립니다. n이 2^31-1까지라면 최대 약 46,000번 나누면 되며, 짝수 제수를 건너뛰면 23,000번입니다. n-1까지 모든 제수를 시험하는 방법은 O(n)이며, 가장 큰 입력에서는 약 20억 단계가 걸립니다.
왜 n의 제곱근까지만 약수를 확인하나요?
약수는 곱이 n인 쌍 d와 n / d로 나타납니다. 두 수가 모두 √n보다 크다면 그 곱은 n보다 커집니다. 따라서 모든 쌍에는 √n 이하인 수가 하나 있고, 그때까지 약수가 나타나지 않으면 n은 소수입니다.
1은 소수인가요?
아니요. 소수는 정확히 두 개의 서로 다른 약수인 1과 자기 자신을 가지며, 1은 약수가 하나뿐입니다. 1을 제외하면 모든 양의 정수의 소인수분해가 유일하게 유지됩니다. 그래서 isPrime(1)은 false를 반환합니다.
매우 큰 수가 소수인지 더 빠르게 판별하는 방법이 있나요?
32비트 숫자 하나라면 √n까지 시험 나눗셈을 해도 충분히 빠릅니다. 수십 자릿수의 숫자에는 프로그램이 약수들을 하나씩 시도하는 대신 몇 가지 모듈러 거듭제곱을 확인하는 밀러-라빈 테스트를 사용합니다. 어떤 한계값까지의 모든 소수를 나열하려면 각 숫자를 따로 검사하는 것보다 에라토스테네스의 체를 사용하는 편이 낫습니다.
비슷한 문제
같은 아이디어를 쓰는 문제입니다. 두세 개를 풀면 패턴이 몸에 익습니다.
Python
def isPrime(n):
# 여기에 코드를 작성하세요케이스 1
케이스 2
케이스 3
입력
n = 29
기대값
true