📚 두 용액
문제
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 복사
5
-2 4 -99 -1 98
예제 출력 1 복사
-99 98
✍ 접근
- 용액의 수가 최악의 경우 100,000 까지 갈 수 있으니 시간복잡도를 고려해야 한다
=> 이중 for문은 쓸 수 없다 - 바보같은 이유로 여러 번 틀렸다
오답코드
import sys
input = sys.stdin.readline
n = int(input())
arr = list(map(int,input().split()))
arr.sort()
res = 2147000000
resa = 0
resb = 0
for i in range(n-1):
a = arr[i]
b = arr[i+1]
c = arr[n-1-i]
if min(abs(a+b), abs(a+c)) < res and i != n-1-i:
if abs(a+b) <= abs(a+c) :
res = abs(a+b)
resa = a
resb = b
else:
res = abs(a+c)
resa = a
resb = c
print(min(resa,resb),max(resa,resb))
- arr을 sort로 정렬하고
- for문을 돌면서 if문을 통해
- res보다 값이 작을 때
- 같은 값이 들어가지 않게 돌려주었다.
- 하위 if문에는 바로 옆 용액과의 합, n-1-i (반대에 있는) 용액과의 합을 계산해더 더 작은 것을 res로 넣어주었다.
- 그리고 res를 갱신하고 resa, resb를 갱신해주었다
😣 문제점
- 예제는 통과했지만 실제로 돌려보면 '틀렸습니다'가 나왔다.
- -99 -98 -1 -2 4 98같은 케이스에서 통과하지 못한다는 것을 깨달았다
따라서 새로운 방법을 고민하게 됐고, 투포인터 방법을 떠올렸다.
정답코드
import sys
input = sys.stdin.readline
n = int(input())
arr = list(map(int,input().split()))
arr.sort()
res = 2147000000
reslt = 0
resrt = 0
lt = 0
rt = n-1
while lt < rt:
if abs(arr[lt]+arr[rt]) < res:
res = abs(arr[lt]+arr[rt])
reslt = arr[lt]
resrt = arr[rt]
if arr[lt]+arr[rt]<0:
lt+=1
elif arr[lt]+arr[rt]>0:
rt-=1
elif arr[lt]+arr[rt] == 0:
break
print(reslt,resrt)
- lt, rt를 투포인터로 삼고
- while문을 돌려준다
- 만약 arr[lt]와 rt의 절대값이 res보다 작으면
res를 갱신하고
reslt와 resrt를 갱신해준다 - 만약 arr[lt]와 arr[rt]를 더했을 때의 값이 0보다 작다면
lt에 1을 더해서 포인터를 옮겨주고 - 값이 0보다 크다면
rt에 1을 빼서 포인터를 옮겨준다 - 🚨 여기서 또 한 번의 실수가 있었다
만약 arr[lt]와 arr[rt]를 더했을 때의 값이 0이라면
다른 값은 볼 필요가 없으므로 빠르게 break 해준다.
- 만약 arr[lt]와 rt의 절대값이 res보다 작으면
⭐ 배움
- 시간복잡도 문제에 두개의 용액이라는 힌트가 주어졌는데도 투포인터를 떠올리지 못했다니.. 반성!
- 가능할 법한 문제를 원천차단하고 실수를 줄이자!
'🏄♀️ 코딩테스트 > 🐍 Python' 카테고리의 다른 글
[ 백준 13549 ] ( python ) 숨바꼭질 3 (0) | 2022.06.22 |
---|---|
[ 백준 1504 ] ( python ) 특정한 최단 경로 (0) | 2022.06.22 |
[ 백준 1946 ] ( python ) 신입 사원 (0) | 2022.06.13 |
[ 백준 1541 ] ( python ) 잃어버린 괄호 (0) | 2022.06.13 |
[ 백준 1931 ] ( python ) 회의실 배정 (0) | 2022.06.13 |