defcheck_prime(x):if x ==1:returnFalsefor i inrange(2,int(math.sqrt(x))+1):if x % i ==0:returnFalsereturnTrue
하지만 O(N)의 시간 복잡도... 조금 더 빠르게 소수 여부를 확인할 순 없을까?
에라토스테네스의 체
주어진 범위 내의 모든 소수를 효율적으로 구하는 알고리즘
처음엔 모든 수가 소수라고 가정하고, 소수가 아닌 수를 하나씩 없애는 방식
절차
(1) 2부터 n까지 자연수 나열
(2) 남은 숫자 중 가장 작은 자연수 p를 선택한 뒤, p 자신을 제외한 p의 배수를 모두 지움
(3) p≤n까지 (2)를 반복
(4) 남은 수는 모두 소수
# 에라토스테네스의 체# 2부터 N까지 숫자 나열
is_prime =[True]*(n +1)# 소수인 경우 True, 아니면 False를 담은 배열
is_prime[1]=False# 1은 소수가 아님# sqrt(N)까지 아래 과정을 반복for i inrange(2,int(math.sqrt(n))+1):# 남은 숫자 중 가장 작은 숫자 -> iif is_prime[i]:# i의 배수를 모두 지움 (i * i 이전의 배수는 이미 지워졌음에 유의)for j inrange(i * i, n +1, i):
is_prime[j]=False
(2) 왜 p의 배수 중 p×p부터 확인하나요?
p×(p−1)까지의 배수는 앞에서 이미 지웠기 때문
e.g., p=3일 때 6=3×2는 2의 배수 지울 때 이미 지워짐
(3) 왜 p≤n까지만 구해도 되나요?
p>n일때 p의 모든 배수는 앞에서 이미 지웠기 때문
e.g., n=20일 때 n=4.xx
이때 4보다 더 큰 5의 배수 10, 20(2의 배수), 15(3의 배수)는 이미 앞에서 지움
시간 복잡도
2부터 N까지 중 소수를 구할 떄
2의 배수 -> 약 2N개의 수를 지움
3의 배수 -> 약 3N개의 수를 지움
5의 배수 -> 약 5N개의 수를 지움
이를 다 더하면 N(i는소수∑i1)개의 수를 지움
(i는소수∑i1)는 수학적으로 loglogN으로 근사됨
체를 만들 때 O(NloglogN)
배열 접근은 O(1)이므로, 체를 한 번 만들어 두면 빠르게 소수 여부 판별 가능
풀이 및 시간 복잡도
에라토스테네스의 체를 사용하지 않은 풀이
import math
defcheck_prime(x):if x ==1:returnFalsefor i inrange(2,int(math.sqrt(x))+1):if x % i ==0:returnFalsereturnTrue
T =int(input())for _ inrange(T):
n =int(input())for i inrange(n //2,0,-1):if check_prime(i)and check_prime(n - i):print(i, n - i)break
시간 복잡도
최대 N번, O(N)의 시간 복잡도를 갖는 check_prime 함수 실행
위 연산을 T회 반복
최종 O(T×NN)
에라토스테네스의 체를 사용한 풀이
import math
T =int(input())
nums =[]for _ inrange(T):
nums.append(int(input()))
max_n =max(nums)# 에라토스테네스의 체# 2부터 N까지 숫자 나열
is_prime =[True]*(max_n +1)# 소수인 경우 True, 아니면 False
is_prime[1]=False# 1은 소수가 아님# sqrt(N)까지 아래 과정을 반복for i inrange(2,int(math.sqrt(max_n))+1):# 남은 숫자 중 가장 작은 숫자 -> iif is_prime[i]:# i의 배수를 모두 지움 (i * i 이전의 배수는 이미 지워졌음에 유의)for j inrange(i * i, max_n +1, i):
is_prime[j]=Falsefor n in nums:for i inrange(n //2,0,-1):if is_prime[i]and is_prime[n - i]:print(i, n - i)break
시간 복잡도
이때 에라토스테네스의 체는 딱 1번만 만들고, 모든 테스트 케이스에서 사용된다는 점에 유의할 것
T번의 테스트 케이스를 입력받으며, 체를 만들 때 필요한 최댓값을 구함: O(T)
에라토스테네스의 체를 만듦: O(NloglogN)
T번의 테스트 케이스에 대해 최대 N번, is_prime 배열에서 소수 여부를 확인: O(T×N)
최종 O(T×N+NloglogN)
실제 소요 시간 비교
맨 밑에 412ms 걸린 풀이가 에라토스테네스의 체를 사용하지 않은 풀이
위에 168ms 걸린 풀이가 에라토스테네스의 체를 사용한 풀이
시간제한이 2초라 두 풀이 다 정답으로 인정됐지만, 암튼 약 3배 빠르다는 점을 알 수 있음