배열이나 문자열에서 위치를 가리키는 포인터 두 개를 두고, 조건에 따라 움직여 가며 답을 찾는 패턴. 추가 메모리 없이(O(1) 공간) 중첩 반복을 한 번의 순회로 줄인다. 보통 정렬된 입력에서 쓴다.
양끝에서 안쪽으로
// 정렬된 배열에서 합이 0인 첫 쌍
function sumZero(arr: number[]) {
let left = 0
let right = arr.length - 1
while (left < right) {
const sum = arr[left] + arr[right]
if (sum === 0) return [arr[left], arr[right]]
if (sum > 0) right-- // 합이 크면 큰 쪽을 줄인다
else left++ // 작으면 작은 쪽을 키운다
}
}같은 방향으로
// 정렬된 배열의 서로 다른 값 개수(입력 배열의 앞쪽을 덮어쓴다)
function countUnique(arr: number[]) {
if (arr.length === 0) return 0
let i = 0
for (let j = 1; j < arr.length; j++) {
if (arr[i] !== arr[j]) arr[++i] = arr[j] // i 앞쪽을 고유값으로 채운다
}
return i + 1
}- 정렬돼 있다는 사실이 "어느 쪽 포인터를 움직일지"를 결정해 준다
- 두 정렬 배열 병합(병합 정렬), 퀵 정렬의 분할(퀵 정렬), 회문(Palindrome) 검사에서도 같은 모양이 나온다
- 두 포인터가 구간의 양끝이 되어 함께 미끄러지면 슬라이딩 윈도우가 된다
다른 패턴은 알고리즘 문제 풀이 접근법.