기초 개념
투 포인터
양쪽에서 좁혀 오기
카드는 작은 수부터 줄을 섰습니다. 합이 13 인 두 장을 찾으세요. 양끝 두 장의 합만 볼 수 있습니다
목표 13
1
3
4
6
8
10
13
왼쪽 끝오른쪽 끝
1 + 13 = 14목표 13 보다 큽니다
합을 본 횟수 1
합을 0번 보고 찾았습니다. 카드가 7장이라 모든 쌍은 21가지입니다.
1 + 13 → 1 + 10 → 3 + 10양끝만 보고 볼 때마다 카드 한 장을 버렸습니다.
모든 쌍 · 7장21번
양끝에서 좁히기 · 7장3번
줄 선 카드의 양끝에서 시작해 가운데로 좁혀 가는 방법 = 투 포인터
왜 버려도 될까
- 합이 크면 — 오른쪽 끝은 남은 카드 중 가장 작은 왼쪽 끝과 더해도 이미 크다. 짝이 없으니 버린다
- 합이 작으면 — 왼쪽 끝은 남은 카드 중 가장 큰 오른쪽 끝과 더해도 아직 작다. 짝이 없으니 버린다
- 그래서 — 가장 작은 카드와 가장 큰 카드가 양끝에 있어야 한다. 줄이 작은 수부터 서 있어야 한다는 뜻이다
줄이 흐트러진 [3, 9, 10, 1] 에서 목표 13 을 찾는다고 해 봅니다. 처음 합 3 + 1 = 4 는 작으니 왼쪽 3 을 버립니다. 그런데 3 + 10 = 13 이 정답이었습니다. 버리면 안 되는 카드를 버린 것입니다.
코드는 끝 두 개를 가리키는 변수 둘이 전부다
누르기 전에 맞혀 보세요. 처음 합 1 + 13 = 14 는 목표 13 보다 큽니다. 다음에 움직이는 변수는 무엇일까요?
10
31
42
63
84
105
136
leftright
다음을 눌러 한 줄씩 넘겨 보세요
left = 0 right = 6
has_pair.py
- 1def has_pair(arr, target):
- 2 left, right = 0, len(arr) - 1
- 3 while left < right:
- 4 total = arr[left] + arr[right]
- 5 if total == target:
- 6 return True
- 7 elif total < target:
- 8 left += 1
- 9 else:
- 10 right -= 1
- 11 return False
0 / 15
left·right— 남은 카드의 양끝 칸 번호. 둘 사이가 아직 안 버린 카드다total— 지금 양끝의 합. 이 값 하나로 어느 쪽을 버릴지 정한다left < right— 두 끝이 만나면 멈춘다. 같은 카드를 두 번 쓰지 않는다
줄이 흐트러진 [3, 9, 10, 1] 에 같은 코드를 돌립니다. 3 + 10 = 13 이 있는데 목표 13 을 찾을까요?
쌍이 있는데 없다고 하거나, 없는데 있다고 한다
- 줄이 안 섰다 — 위 문제처럼 쌍을 놓친다. 먼저
arr.sort()로 줄을 세운다. 줄 세우는 데 N log N 이 든다 left <= right— 같은 카드를 두 번 쓴다.[1, 6, 9]에서 목표 12 는 쌍이 없는데 6 + 6 을 쌍이라고 한다- 끝까지 못 찾으면 — 두 끝이 만나서 반복문이 끝난다. 그때
return False
문제에서 이 말이 보이면
정렬돼 있다두 수의 합양끝에서 좁힌다
다음 장에서는 창문을 밀면서 보는 슬라이딩 윈도우를 봅니다.