Skip to content
This repository was archived by the owner on Mar 18, 2024. It is now read-only.

[2023-09-15] sumin #208 #228

Merged
merged 1 commit into from
Sep 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions BOJ/골드바흐의 추측/sumin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""
풀이 시간: 22분

<input>
t: 테스트케이스
n: 찾아야 하는 골드바흐 파티션의 합이 되는 짝수(4 ≤ n ≤ 10,000)

<solution>
합이 n이 되는 짝수를 어떻게 찾을 수 있을까?
- 2 ~ 최대 10,000개까지의 소수 중 합이 n이 되게 하는 두 소수를 찾기 위해서 투포인터를 사용할 수 있다.
- 소수가 정렬돼있는 상태이기 때문에 left는 시작 인덱스, right은 끝 인덱스로 초기화 후, 두 소수의 합을 계속해서 target과 비교하며 포인터를 이동시킨다.

<시간복잡도>
O(nlog(logn)): 에라토스테네스의체
find_parition 함수는 최대 O(n)


뭔가 더 최적화할 수 있는 방법이 있을 것 같은데 생각이 안남.... 여러분의 신박한 풀이 기다립니다..
"""

import sys
input = sys.stdin.readline
from typing import List

def find_prime_numbers(mx: int) -> List:
"""
mx: 2 ~ mx까지 중 소수인 수
"""
arr = [True] * (mx+1)
arr[0] = arr[1] = False # 0과 1은 소수가 아님

# 에라토스테네스의 체
for i in range(2, int(mx**(1/2))+1):
if arr[i]: # i가 소수인 경우
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[i for i in range(len(arr)) if arr[I]] 해당 검사를 다시 len(arr) 만큼 해줘야하니 여기서 소수를 리스트에 하나씩 append 하는 형식으로 최적화를 할 수 있을 것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 그럼 새로운 리스트를 하나 만들어서 i를 append 해주고 해당 리스트를 반환하는 식으로 해야겠네요..!
감사합니다 우열님~!!!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Woo-Yeol 에라토스테네스의 체는 소거법이기 때문에 일단 모든 수가 소수라고 가정 하고 순회하며 소수가 아닌 수들을 지워줘야 최종적으로 소수인 값들을 구할 수 있기 때문에 여기서 append는 해서 소수를 구하기는 어려울 것 같습니다.

다만 34번 라인의 주석을 i가 현재 소수로 표시되어있는 경우라고 바꿔주면 표현이 명확해질 수 있겠네요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 제가 위에 코멘트 남긴게 pending으로 돼있었군요!
지수님 말씀하신 34번째 라인에서 i를 append해주는 것만으로도 위에 소수를 입력받는 list를 하나 만들어주면 가능해요!

j = 2
while i * j <= mx:
arr[i*j] = False
j += 1

return [i for i in range(len(arr)) if arr[i]]


def find_partition(target: int, prime_number: List) -> List:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

투 포인터를 통해 접근하는 방법도 존재 할 수 있었군요! 저는 그냥 해시테이블을 통해서 있어야할 소수 값이 존재하는지를 확인하는 방식으로 접근하고 결과값의 최소 차이를 기억하는 방식을 사용했었는데 투 포인터를 사용하면 조금 더 시간 복잡도를 개선 할 수 있을 것 같습니다! 고생하셨습니다 수민님!!

"""
target: 찾아야 하는 골드바흐 파티션의 합이 되는 짝수
prime_number: n까지의 소수 배열
"""
left, right = 0, len(prime_number)-1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right을 target으로 두어도 될 것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

target은 실제 값이고 right은 끝인덱스를 의미하는거라 target으로 두면 안돼요 지수님!

diff = target # 현재까지 찾은 최소 차이
result = [0, 0] # 최소 차이를 가지는 골드바흐 파티션

# 투포인터
while left <= right:
cur_sum = prime_number[left] + prime_number[right]
if cur_sum == target: # 두 소수의 합이 target이 될 때
if diff > prime_number[right] - prime_number[left]: # 최소 차이 업데이트
diff = prime_number[right] - prime_number[left]
result[0], result[1] = prime_number[left], prime_number[right]
left += 1
elif cur_sum < target: # 두 소수의 합이 target보다 작다면 left를 증가
left += 1
else: # 두 소수의 합이 target보다 크다면 right를 감소
right -= 1
return result

# 테스트 케이스의 수
t = int(input())
primes = find_prime_numbers(10000) # 입력으로 들어올 수 있는 가장 큰 n은 10,000이기 때문에 미리 10,000까지 모든 소수를 구해둠
for _ in range(t):
n = int(input())
print(*find_partition(n, primes))