백준 2467 - 용액 (Python3)
코드
n = int(input())
arr = list(map(int, input().split()))
# 최댓값 생성
INF = int(100e9)
# 두 용액을 담을 리스트
target = []
def solution(arr, target):
# 두 용액의 합을 담을 변수
tot = INF
# 반복문을 이용하여
# i번째 용액부터 n-1번째 용액까지
# 각각 용액 둘의 합을 구해서
# 0에 가장 가까운 값을 이진 탐색으로 찾음
for i in range(n-1):
# 시작 용액은 반복시 마다 바뀜
start = i+1
end = n-1
# 현재 용액
now = arr[i]
while start <= end:
mid = (start + end) // 2
# 현재 용액 + 이진 탐색으로 찾은 용액
# 두 용액의 합을 담을 임시 변수
# arr[mid] : 이진 탐색으로 찾은 용액
tmp = now + arr[mid]
# 합이 0이면 값을 찾았으므로
# 함수를 종료하고 target을 반환함
if tmp == 0:
target = [arr[i], arr[mid]]
return target
# tot가 값이 abs(tmp)보다 크다면
# abs(tmp)로 업데이트
# target에 두 값을 넣고 반환
# 0에 가장 가까울 것이므로 절댓값을 취해줌
if tot > abs(tmp):
tot = abs(tmp)
target = [arr[i], arr[mid]]
if tmp < 0:
start = mid + 1
else:
end = mid - 1
return target
print(*solution(arr, target))
문제 해설
이진 탐색 문제.
백준 2470 - 두 용액 링크의 문제와 거의 똑같은 문제이나, 카테고리 분류가 링크의 문제는 투 포인터에 있고, 이번 문제는 이진 탐색에 있어서 이진 탐색으로 풀었다.
for문에 while문까지 사용하여 이진 탐색을 구현하는 문제는 처음 접해봐서 그런지 이 로직을 생각하는게 생각보다 힘들었다. 그래도 이후 로직은 문제를 꼼꼼히 읽어보면 천천히 구현할 수 있었으나, 함정은 다른 곳에 있었다.
주피터 노트북에서 예시를 풀어도 항상 정답과 일치하였고, 참고 코드를 봐도 코드 자체는 다르더라도 로직이 다른 곳은 없는데 ‘‘틀렸습니다’’ 만 무한으로 나오는 걸 보면서 1시간 정도는 시간을 잡아먹혔다. 이유는 아래와 같았다.
난 이때까지 INF라는 무한대의 값을 설정할 때 항상
INF = int(1e9)
위와 같이 생성하였다. 이는 곧 1000000000이라는 숫자이다. 즉, 10억이라는 엄청 큰 숫자이고 주어지는 범위가 이를 넘기는 경우는 거의 없으니 항상 이 값을 지정하였다. 허나, 이 문제는 이 범위로는 만족할 수 없는 문제였다.
용액의 범위가 -10억 ~ +10억 사이 이므로 두 용액 합의 절댓값이 10억을 넘기는 경우가 허다하게 발생할 수 있었다. 이렇게 큰 범위를 간과하고 문제에 접근한 채로 시간만 잔뜩 잡아먹은 것이다.
이 문제를 통하여 어떤 문제를 접하더라도 문제에서 주어지는 조건을 하나 하나 꼼꼼히 따져보는 버릇이 필요하다는 것을 절실히 깨달았다. 앞으로 모든 문제를 꼼꼼히 천천히 읽는 습관을 가져야겠다.
댓글남기기