[Baekjoon] # 2470: 두 용액
두 용액
문제
1
2
3
4
5
6
7
8
9
산성 용액의 특성값은 1부터 1,000,000,000까지의 양의 정수로 나타내고,
알칼리성 용액의 특성값은 -1부터 -1,000,000,000까지의 음의 정수로 나타낸다.
산성 용액과 알칼리성 용액의 특성값이 주어졌을 때,
이 중 두 개의 서로 다른 용액을 혼합하여 특성값이 0에 가장 가까운 용액을 만들어내는
두 용액을 찾는 프로그램을 작성하시오.
예제
- 입력
첫째 줄에는 전체 용액의 수 N이 입력된다.
N은 2 이상 100,000 이하이다.
둘째 줄에는 용액의 특성값을 나타내는 N개의 정수가 빈칸을 사이에 두고 주어진다.
이 수들은 모두 -1,000,000,000 이상 1,000,000,000 이하이다.
N개의 용액들의 특성값은 모두 다르고, 산성 용액만으로나 알칼리성 용액만으로 입력이 주어지는 경우도 있을 수 있다.
1
2
5
-2 4 -99 -1 98
- 출력
첫째 줄에 특성값이 0에 가장 가까운 용액을 만들어내는 두 용액의 특성값을 출력한다.
출력해야 하는 두 용액은 특성값의 오름차순으로 출력한다.
특성값이 0에 가장 가까운 용액을 만들어내는 경우가 두 개 이상일 경우에는 그 중 아무것이나 하나를 출력한다.
1
-99 98
Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def get_inputs():
import sys
input_data = sys.stdin.read()
inputs = input_data.splitlines()
item_count = int(inputs[0])
data = list(map(int, inputs[1].split(" ")))
return item_count, data
def solution(item_count, data):
# 주어진 배열 오름차순으로 정렬
data.sort()
left, right = 0, item_count - 1
# 최솟값 저장
closest_distance = float("inf")
answer = None
while left < right:
sum = data[left] + data[right]
# `sum`이 `target = 0`과 같으면 return
if sum == 0:
return str(data[left]) + " " + str(data[right])
distance = abs(sum)
# `target`과 가장 가까운 값인 경우, 최솟값 갱신
if closest_distance > distance:
answer = [data[left], data[right]]
closest_distance = distance
# 배열이 정렬이 되어 있으므로
# `sum`이 `target`보다 큰 경우, 더 작은 수의 포인터
if sum > 0:
right -= 1
# `sum`이 `target`보다 작은 경우, 더 큰 수의 포인터
else:
left += 1
return str(answer[0]) + " " + str(answer[1])
def main():
item_count, data = get_inputs()
result = solution(item_count, data)
print(result)
if __name__ == "__main__":
main()
해결 방법
Two Pointer
위 문제는 두 개의 포인터를 사용해서 배열을 탐색해가는 Two Pointer
패턴으로 해결할 수 있다.
Two Pointer
는 아래와 같은 문제를 해결할 때 사용한다.
- 정렬된 배열에서 두 수의 합이
target
과 같거나 가까운 쌍 찾기 - 배열에서 중복된 원소 제거하기
- 회문(
Palindrome
) 확인하기
해결 과정
아래 3 가지 과정을 통해서 target
과 가장 가까운 값을 찾을 수 있다.
- 정렬 및 초기화
- 주어진 배열을 오름차순으로 정렬
- 배열의 양 끝에 두 포인터(
left, right
) 위치 closest_distance
와answer
변수 초기화
- 합 계산 및 비교
- 두 포인터가 가리키는 값의 합 계산:
sum = arr[left] + arr[right]
- 합이
target
과 같으면 즉시 해당 값 반환 - 다르다면
distance = abs(sum - target)
을 계산하여closest_distance
와 비교 후 필요시answer
갱신
- 두 포인터가 가리키는 값의 합 계산:
- 포인터 이동
sum > target
: 오른쪽 포인터를 왼쪽으로 이동 (right -= 1
)sum < target
: 왼쪽 포인터를 오른쪽으로 이동 (left += 1
)left < right
일 때까지 2번 과정부터 반복
배열이 정렬되어 있기 때문에,
합이 목표값보다 크면 더 작은 값을, 작으면 더 큰 값을 선택하며 target
에 가까워질 수 있다.
의사 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Function solution(item_count, array):
// 배열을 오름차순으로 정렬
Sort array
// 양쪽 끝에서 시작하는 두 포인터 초기화
left = 0
right = item_count - 1
// 가장 가까운 거리와 정답을 저장할 변수 초기화
closest_distance = 무한대
answer = null
// 두 포인터가 교차할 때까지 반복
While left < right:
// 현재 두 수의 합 계산
sum = array[left] + array[right]
// 합이 0이면 즉시 해당 두 수를 문자열로 반환
If sum equals 0:
Return array[left]와 array[right]를 문자열로 변환하여 공백으로 연결
// 현재 합의 절대값(0과의 거리) 계산
distance = |sum|
// 이전까지의 최소 거리보다 현재 거리가 더 작으면 정답 업데이트
If closest_distance > distance:
answer = [array[left], array[right]]
closest_distance = distance
// 합이 양수면 오른쪽 포인터를 왼쪽으로 이동
If sum > 0:
right = right - 1
// 합이 음수면 왼쪽 포인터를 오른쪽으로 이동
Else:
left = left + 1
// 최종적으로 찾은 두 수를 문자열로 변환하여 반환
Return answer[0]와 answer[1]을 문자열로 변환하여 공백으로 연결
URL
This post is licensed under CC BY 4.0 by the author.