(알고공부 D-4)
# "1000 이하의 소수를 나열하기" 코드 이해하기
<코드>
# 1000 이하의 소수를 나열하기 (알고리즘 개선 2)
ptr = 0 # 이미 찾은 소수의 개수
prime = [None] * 500 # 소수를 저장하는 배열
prime[ptr] = 2 # 2는 소수
ptr += 1
prime[ptr] = 3 # 3은 소수
ptr += 1
for n in range(5, 1001, 2): # 홀수만을 대상으로 설정
i = 1
while prime[i] * prime[i] <= n:
if n % prime[i] == 0: # 나누어 떨어지므로 소수가 아님
break # 반복 중단
i += 1
else: # 끝까지 나누어 떨어지지 않았다면
prime[ptr] = n # 소수로 배열에 등록
ptr += 1
for i in range(ptr): # 소수 출력
print(prime[i])
(설명)
n의 순서쌍 p,q에서 p>=q일 때 p가 n으로 나누어떨어지는지 확인하면 q는 자동적으로 n으로 나누어떨어진다고 판단할 수 있다. 예시로 16은 순서쌍 (2,8), (4,4), (8,2)가 있는데 여기서 (2,8)과 (8,2)는 대칭구조이다. 우리는 n인 16이 2로 나누어떨어진다는걸 확인하면 저절로 8로도 나누어떨어진다는걸 순서쌍 (8,2)로 확인할 수 있다. 그러므로 p로 나누어떨어지는지 확인하면 되는데, 이 경우 대칭인 순서쌍의 경우는 제외한다. 즉 여기서는 (2,8), (4,4) 범위에서만 나눗셈을 수행한다. 즉 순서쌍 (sqrt(n), sqrt(n)) (* 16의 경우 (4,4)) 이하의 범위까지 p로 나눗셈을 시도하면 된다. 이걸 소수 판단에 응용하면, 어떠한 정수 n이 sqrt(n) 이하의 소수들로 나누어떨어지지 않는다면 소수라고 판단할 수 있다. 다시 말해 정수 n은 n의 제곱근 이하의 어떤 소수로도 나누어떨어지지 않을 때 소수이다.
이걸 응용한 것이 바로 해당 코드이다. 이 코드에서 우리가 고려해야 할 점이 있다. 5부터 1000까지의 홀수 중에서 소수인지 판단하기 위해서는 for문으로 반복해서 판단해줄 수 있다. 소수 판단은 판단하고자 하는 숫자 -1까지의 소수로 나누어떨어지는지 유무로 확인할 수 있다. 그렇다면 5 ~ 1000 사이 정수를 for문으로 소수인지 판단하고 소수가 나올 때마다 배열에 넣어준 다음 그 배열 원소들로 정수가 나뉘는지 확인해야 한다. 여기서 우리는 앞서 설명한 순서쌍 (sqrt(n), sqrt(n))을 사용할 수 있다.
코드를 보면 while문에서 i = prime[i] * prime[i] <= n: (소수의 곱 <= n)이다.
여기서 while prime[i] * prime[i] <= n: 반복문은 앞서 말했듯이 어떠한 정수 a가 sqrt(n) 이하의 소수들로 나누어떨어지지 않는다면 소수라고 판단할 수 있기 위함이다.
이에 대해 설명하기 위해 필자는 앞서 설명했던 순서쌍 (sqrt(n), sqrt(n))을 독특하게 이해해봤다. 앞서 어떠한 정수 n이 sqrt(n) 이하의 소수들로 나누어떨어지지 않는다면 소수라고 판단할 수 있다고 했다. 이 구조를 이해하기 위해 임의의 정수 77을 소수 판단한다고 생각해보자.
(* prime[1] = 3, prime[2] = 5, prime[3] = 7, prime[4] = 11)
77의 경우 prime[1], prime[2]로는 나누어떨어지지 않으나, prime[3]인 7에서 나누어떨어져 소수가 아니다. 필자는 77의 경우 sqrt(n)을 prime[3]으로 해석하였고, 이하의 소수로 prime[1], prime[2]가 추가로 있다고 생각했다. 즉 77이 소수인지 아닌지에 대해 판단하기 위해서는 prime 배열원소 1부터 3로 나누어떨어지는지 판단하는 것이다. 이는 앞서 16을 소수판단하기 위해서는 2, 4로만 나누어본다고 한 말과 일맥상통한다.
prime[i] * prime[i] <= n로 한 이유는 정수 n이 소수이려면 n 제곱근 이하의 어떤 소수로도 나누어떨어지지 않아야하기 때문이다. 원래는 prime[i] <= sqrt(n)으로 해야 하나 편의상 저렇게 한 것이다.
코드를 보면 소수 판단은 배열 인덱스 1인 3부터 시작하고, 소수가 생긴다면 배열에 등록하면서 1000까지 반복한다.
소수판단하는 과정과 소수로 판별된 정수를 배열에 등록하는 과정은 각주에 잘 설명되어 있으니 참조하면 된다.
일단... 졸면서 이해한 코드라서 제대로 이해 못한거같기도 하고.. 그냥 내 능지문제인거같아서 아침에 다시 차근차근 뜯어서 이해해봐야지
설명을 쓰긴 했지만 prime[i] * prime[i]로 해야하는 이유가 아직 딱 와닿지가 않음
# 내일 목표
- 이 문제 제대로 이해해보고 혼자서 짜보기
- 컴과 인강 2개 듣기
- 백준 3문제
- do it 2강 복습
퇴고없이 의식의 흐름으로 작성한거니 이상할 수있따는거 인정.. 혹시라도 저 설명서에서 내가 치명적인 잘못을 했다면 알려주라...
하루에 열 문제 씩 풀어조
하루 3문제만 해도 2시간 뚝딱임!!!
야호
개고수네 어케 3문제를 2시간에
저 브론즈 문제푸는데여 ㅇㅅㅇ...ㅜ
해당 댓글은 삭제되었습니다.
헉 각주 감사해요!! 왜 저렇게 썻지....ㅋㅋㅋㅋㅋㅋ 일단 저거 그냥 복붙한거라 띄어쓰기가 엉망이라는점 염두해주시고, 제가 이따 일어나서 코드 다시 올려볼게요 ㅋ쿠ㅜㅜ 그리고 if n % prime[i] == 0: 즉 소수가 아닐 때, 더 이상 다른 소수(배열원소)로 나눠줄 필요가 없기 때문에(어짜피 나눠줘봣자 소수가 아니니 헛짓임) 바로 break로
빠져나가고, 만약 if 조건식이 아닐땐 i+=1을한다. 그러니까 else: i+=1로 해석할 수 있을 것 같아요...! 즉 n%prime[i]이 0이 아닐 때 그 다음 배열 원소들로 또 나눠줘야하니 i+=1을 한다음 다시 while문으로 소수 판단 if문 거치고 ... 이 과정을 배열 원소가 끝날때까지 하는거죠! 만약 더이상 나눠줄 원소들이 없으면 els
Else문을 실행해서 새로운 소수를 배열에 넣는...!
헉 저도... 뉴비라서...ㅋㅋㅋㅋ 파이썬 겨우 뗀다음 알고리즘 시작한지 5일째라 ㅋㅋㅋㅋ.. 전 do it 자료구조와 함께 배우는 알고리즘 책으로 공부중이고 이 코드는 2강에 나와요! 한번 언어 공부 하신다음 보시는더 추천드려요 ㅎㅎ
열심히 하시네요
헉 고마워요 님아... 잘 이해한거 맞겟죠 저거...ㅋㅋㅋㅋ 알고 시작한지 4일만에 저 문제로 벽느낌 ㅋㅋㅋ...
해당 댓글은 삭제되었습니다.
ㄹㅇ이해하느라 뒤지는줄 알앗음...다들 어캐 저거 보자마자 이해함...
헐 그런가... ㅜ 알고공부 1달후엔 저정도는 바로 딱 이해하게 될 수준이 되도록 열심히 해봐야겟네... 아직은 컴퓨터적 사고가 부족한듯 ㄹㅇ.. 암튼 알려줘서 진짜 고맙다ㅜㅜ