두 포인터 (양쪽 끝)

발행: (2026년 1월 9일 오후 07:24 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

개요

이 패턴은 데이터 구조(배열 또는 문자열)의 양쪽 끝에서 시작하여 서로를 향해 이동하는 두 개의 포인터를 사용합니다. 주로 다음과 같은 경우에 사용됩니다:

  • 양쪽 끝 모두에서 순서가 중요할 때
  • 데이터가 정렬되어 있거나 대칭일 때
  • 쌍이나 대칭 위치를 확인할 때
  • 시간 복잡도를 O(N²) 에서 O(N) 으로 줄이고 싶을 때

포인터 설정

  • left → 인덱스 0에서 시작
  • right → 인덱스 n – 1에서 시작

반복 조건

left < right인 동안 계속합니다.

포인터 이동 로직

  • 현재 조건이 만족되면: 답을 업데이트하고 포인터를 이동합니다.
  • 값이 너무 작으면: left를 앞으로 이동합니다.
  • 값이 너무 크면: right를 뒤로 이동합니다.

시간 및 공간

  • 시간 복잡도: O(N)
  • 공간 복잡도: O(1)

예시

예시 1: Two Sum (정렬된 배열)

문제:
정렬된 배열이 주어졌을 때, 합이 목표값과 같은 쌍이 존재하는지 판단합니다.

로직:

  • 합이 목표값보다 작으면 left를 증가시켜 더 큰 합을 만듭니다.
  • 합이 목표값보다 크면 right를 감소시켜 더 작은 합을 만듭니다.
def two_sum_sorted(nums, target):
    left = 0
    right = len(nums) - 1

    while left < right:
        current_sum = nums[left] + nums[right]

        if current_sum == target:
            return True
        elif current_sum < target:
            left += 1
        else:
            right -= 1

    return False

예시 2: 팰린드롬 검사

문제:
문자열이 팰린드롬인지 확인합니다.

로직:

  • 대칭 위치에 있는 문자들이 일치해야 합니다.
  • 불일치가 발생하면 즉시 False를 반환합니다.
def is_palindrome(s):
    left = 0
    right = len(s) - 1

    while left < right:
        if s[left] != s[right]:
            return False
        left += 1
        right -= 1

    return True

예시 3: 최대 물 저장 용량(Container With Most Water)

문제:
두 개의 수직선을 선택해 x축과 함께 물을 가장 많이 담을 수 있는 용기를 찾습니다.

로직:

  • 면적은 너비와 작은 높이에 의해 결정됩니다.
  • 면적을 늘리기 위해 작은 높이를 가진 포인터를 이동합니다.
def max_area(height):
    left = 0
    right = len(height) - 1
    max_water = 0

    while left < right:
        width = right - left
        current_height = min(height[left], height[right])
        max_water = max(max_water, width * current_height)

        if height[left] < height[right]:
            left += 1
        else:
            right -= 1

    return max_water

예시 4: 제자리 배열 역순 (Reverse Array In‑Place)

문제:
추가 공간을 사용하지 않고 배열을 역순으로 만듭니다.

로직:

  • 대칭 위치에 있는 요소들을 교환합니다.
  • 포인터가 만날 때까지 안쪽으로 이동합니다.
def reverse_array(arr):
    left = 0
    right = len(arr) - 1

    while left < right:
        arr[left], arr[right] = arr[right], arr[left]
        left += 1
        right -= 1

    return arr

식별 체크리스트

다음 질문을 해보세요:

  • 두 요소를 함께 비교하고 있나요?
  • 양쪽 끝의 값에 관심이 있나요?
  • 매 단계마다 한쪽을 버릴 수 있나요?
  • 데이터가 정렬되어 있거나 대칭인가요?

답이 라면 이 패턴이 적합합니다.

요약

  • 두 포인터가 반대쪽 끝에서 시작합니다.
  • 두 포인터 모두 안쪽으로 이동합니다.
  • 각 반복마다 불가능한 경우를 제거합니다.

이 접근법은 깔끔하고 최적이며 이해하기 쉽습니다.

Back to Blog

관련 글

더 보기 »

배열에서 첫 번째 반복 요소 (C++)

왜 내 첫 번째 접근 방식이 잘못됐는가 — 그리고 그것을 어떻게 고쳤는가 문제 명확화 매우 중요 작업은 첫 번째 등장 인덱스가 작은 요소를 찾는 것입니다...