[백준] 2470번 두 용액 | 파이썬 Python

문제

KOI 부설 과학연구소에서는 많은 종류의 산성 용액과 알칼리성 용액을 보유하고 있다. 각 용액에는 그 용액의 특성을 나타내는 하나의 정수가 주어져있다. 산성 용액의 특성값은 1부터 1,000,000,000까지의 양의 정수로 나타내고, 알칼리성 용액의 특성값은 -1부터 -1,000,000,000까지의 음의 정수로 나타낸다.

같은 양의 두 용액을 혼합한 용액의 특성값은 혼합에 사용된 각 용액의 특성값의 합으로 정의한다. 이 연구소에서는 같은 양의 두 용액을 혼합하여 특성값이 0에 가장 가까운 용액을 만들려고 한다.

예를 들어, 주어진 용액들의 특성값이 [-2, 4, -99, -1, 98]인 경우에는 특성값이 -99인 용액과 특성값이 98인 용액을 혼합하면 특성값이 -1인 용액을 만들 수 있고, 이 용액이 특성값이 0에 가장 가까운 용액이다. 참고로, 두 종류의 알칼리성 용액만으로나 혹은 두 종류의 산성 용액만으로 특성값이 0에 가장 가까운 혼합 용액을 만드는 경우도 존재할 수 있다.

산성 용액과 알칼리성 용액의 특성값이 주어졌을 때, 이 중 두 개의 서로 다른 용액을 혼합하여 특성값이 0에 가장 가까운 용액을 만들어내는 두 용액을 찾는 프로그램을 작성하시오.

 

입력

첫째 줄에는 전체 용액의 수 N이 입력된다. N은 2 이상 100,000 이하이다. 둘째 줄에는 용액의 특성값을 나타내는 N개의 정수가 빈칸을 사이에 두고 주어진다. 이 수들은 모두 -1,000,000,000 이상 1,000,000,000 이하이다. N개의 용액들의 특성값은 모두 다르고, 산성 용액만으로나 알칼리성 용액만으로 입력이 주어지는 경우도 있을 수 있다.

 

출력

첫째 줄에 특성값이 0에 가장 가까운 용액을 만들어내는 두 용액의 특성값을 출력한다. 출력해야 하는 두 용액은 특성값의 오름차순으로 출력한다. 특성값이 0에 가장 가까운 용액을 만들어내는 경우가 두 개 이상일 경우에는 그 중 아무것이나 하나를 출력한다.

 

예제

 

나의 풀이1

N = int(input())
nums = sorted(list(map(int, input().split())))

left, right = 0, N-1
value = 1e9
result = [0, 0]

while left < right:
    sum = abs(nums[left] + nums[right])

    if sum < value:
        value = sum
        result = [nums[left], nums[right]]
        left += 1
        right -= 1
    elif sum > value:
        right -= 1
    elif sum < value:
        left += 1

print(nums)
print(result[0], result[1])
  • 두 포인터를 리스트의 양 끝에 놓고 안쪽으로 이동하는 방법으로 풀어봤는데 틀린 풀이가 됐다.

 

나의 풀이2

N = int(input())
nums = sorted(list(map(int, input().split())))

end = N-1
value = int(1e9)
result = [0, 0]

for start in range(N-1):
    while start < end and abs(nums[start] + nums[end]) < value:
        value = abs(nums[start] + nums[end])
        result = [nums[start], nums[end]]
        end -= 1

print(result[0], result[1])
  • `start`는 for문으로 하나씩 증가하고, `end`는 while문에서 하나씩 감소하는 방법을 사용했는데 또 틀렸다는 결과가 나왔다.

 

나의 풀이3

N = int(input())
nums = sorted(list(map(int, input().split())))

mn = int(1e9)
result = [0, 0]

for start in range(N-1):
    end = N-1
    temp_mn = int(1e9)
    temp_result = [0, 0]

    while start < end and abs(nums[start] + nums[end]) < temp_mn:
        temp_mn = abs(nums[start] + nums[end])
        temp_result = [nums[start], nums[end]]
        end -= 1
    
    if temp_mn < mn:
        mn = temp_mn
        result = temp_result

print(result[0], result[1])
  • `start`는 for문으로 하나씩 증가하고, `end`는 while문에서 하나씩 감소하는 방법을 사용하고, for문을 넘어갈 때마다 `end`, `temp_mn` 등 변수를 초기화하는 과정을 추가했다.
  • 이번에는 시간 초과로 실패했다.

 

다른 사람의 풀이

N = int(input())
nums = sorted(list(map(int, input().split())))

left, right = 0, N-1
min = abs(nums[left] + nums[right])
result = [nums[left], nums[right]]

while left < right:
    sum = nums[left] + nums[right]
    
    if abs(sum) < min:
        min = abs(sum)
        result = [nums[left], nums[right]]
        
    if sum > 0:
        right -= 1
    else:
        left += 1

print(result[0], result[1])
  • 두 포인터를 리스트의 양쪽 끝에 생성하고 두 포인터의 합이 `0`보다 큰지 작은지에 따라서 하나의 포인터를 이동하며 특정값을 조정한다. 새로 계산한 두 포인터의 합이 기존 값보다 `0`에 가깝다면 `min`, `result`를 수정한다.
  • 내가 첫 번째로 접근했던 방법과 비슷하지만, 포인터를 움직이는 if문과 `0`에 가장 특정값을 계산하는 if문이 분리되어야 한다는 점과 포인터를 움직이는 기준이 `0`보다 큰지 작은지로 설정해야 된다는 점이 달랐다.