🏄‍♀️ 코딩테스트/🐍 Python

[ 백준 2470 ] ( python ) 두 용액

Po_tta_tt0 2022. 6. 15. 11:46
반응형

 

📚 두 용액

 

문제

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 해준다.

 

 

⭐ 배움

  • 시간복잡도 문제에 두개의 용액이라는 힌트가 주어졌는데도 투포인터를 떠올리지 못했다니.. 반성!
  • 가능할 법한 문제를 원천차단하고 실수를 줄이자!

 

 

 

반응형