2024. 6. 12. 21:15ㆍ개발의 흔적/코딩테스트
문제: 소수(에라토스테네스 체)
자연수 N이 입력되면 1부터 N까지의 소수의 개수를 출력하는 프로그램을 작성하세요. 만약 20이 입력되면 1부터 20까지의 소수는 2, 3, 5, 7, 11, 13, 17, 19로 총 8개입니다. 제한시간은 1초입니다.
<입력설명>
첫 줄에 자연수의 개수 N(2<=N<=200,000)이 주어집니다.
<출력설명>
첫 줄에 소수의 개수를 출력합니다.
- 입력예제 20
- 출력예제 8
블로그 앞의 글들에서 N의 약수를 찾을때에, 내가 고안한 방법의 시간복잡도는 O(sqrt(N))이었다.
그리고 그동안 소수를 구할때 약수를 구하는 방법에서 조금 변형해서 코드를 작성해왔다.
import sys
input = sys.stdin.readline
from math import sqrt
N = int(input())
median = sqrt(N)
cnt_not_era = 0
for i in range(2, N+1):
if i == 2:
continue
median = int(sqrt(i))
cnt_yak = 0
for j in range(2, median+1):
if i%j == 0:
cnt_not_era += 1
break
print(N-cnt_not_era-1)
N의 소수를 구하기 위해서, 2부터 N까지 쭉 for문을 도는데,
for문안의 수 (i)가 2~sqrt(N) 까지 약수가 존재한다면 배제하는 것이다.
https://leerosepark.tistory.com/25 를 보면 약수를 구하는 코드를 알 수 있다.
그렇다면 이러한 코드의 시간복잡도는 어떻게 될까?
- 외부 루프 (for i in range(2, N+1)):
- 이 루프는 N-1번 반복됩니다.
- 내부 루프 (for j in range(2, median+1)):
- 각 i에 대해 내부 루프는 최대 sqrt(i)번 반복됩니다.
- 최악의 경우 i는 N이 될 수 있으므로 내부 루프는 최대 sqrt(N)번 반복됩니다
- 최종적으로 Nsqrt(N), 즉 N^(3/2)의 시간복잡도를 가진다.
그러나 위 문제처럼 N이 200,000일때는, 200,000 * sqrt(200,000) ~= 200,000 * sqrt(20) * 100 ~= 20,000,000 * 5 = 100,000,000가 된다.
보통 2초의 시간제한이 있다면, 어림잡아 시간복잡도가 2억이라 가정하기때문에, 위 구현으로 가능하나, 역시나 위험부담이 있다.
그런 고민과 함께 문제 제목인 '아레스토테네스 체'를 구글에 검색해보았는데 깜짝놀랐다.
N ( ln ( ln N ) ) 의 시간복잡도로 소수를 찾는 코드를 구현 할 수 있었다.
에라토스테네스의 체
Sieve of Eratosthenes 고대 그리스의 수학자 에라토스테네스 가 만들어 낸 소수 를 찾는 방법.
namu.wiki
2~N까지의 순서로 탐색을하는데, 현 탐색하는 숫자의 배수들을 제거해 나가는 방법이다.
처음인 2의 차례에선 2를 제외한 모든 짝수들이 제거될것이고,
3의 차례에서는 3의배수들(6의 배수는 이미 2에서 제거됨)이 제거 될 것이다.
그렇게 되면 4는 제거되었으므로 자연스럽게 건너뛰게 되고,
그다음 차례인 5는 반드시 소수일 것이며 (5보다 작은 소수들의 배수가 아니므로) 5의 배수들을 제거한다.
2~N까지 순차적으로 for문을 돌리면서 배수를 제거하는 작업을 한다면,
다음 i의 배수를 제거하게 될때, 그 i는 반드시 소수일 것이다.
import sys
input = sys.stdin.readline
N = int(input())
num_list = [0] * (N+1)
cnt = 0
for idx in range(2, N+1):
if num_list[idx] == 0:
cnt+=1
for i in range(idx, N+1 ,idx):
num_list[i] += 1
print(cnt)

이러한 수학적인 이유로 시간복잡도가 다음과 같이 되니, 위 방법을 기억해두자.
'개발의 흔적 > 코딩테스트' 카테고리의 다른 글
| [구현] (2-9) Counter()를 이용해 list를 hash로! (0) | 2024.06.14 |
|---|---|
| [구현] (2-8) N까지의 소수 구하기 vs 한 숫자의 소수여부 판별 (1) | 2024.06.12 |
| [구현] (2-5) 정다면체 주사위 (2) | 2024.06.11 |
| [구현] (2-4) 평균과 편차 (0) | 2024.06.11 |
| [구현] (2-3) combinations의 시간복잡도 (0) | 2024.06.11 |