Files
hello-algo/ko/docs/chapter_searching/binary_search_edge.md
T
Yudong Jin 2f561d3d51 feat(ko): add the Korean online edition (#2006)
* feat(ko): add the complete Korean online edition

* Use UTF-8 for Python CI output on Windows

* Remove print-book promotion from the Korean site

* fix(ko): preserve emphasis before Korean particles
2026-10-29 03:46:43 +08:00

3.1 KiB

이진 탐색으로 경계 찾기

왼쪽 경계 찾기

!!! question "문제"

중복 원소를 포함할 수 있는 길이 $n$의 정렬된 배열 `nums`가 주어진다. 배열에서 가장 왼쪽에 있는 원소 `target`의 인덱스를 반환하라. 해당 원소가 없으면 $-1$을 반환하라.

이진 탐색으로 삽입 위치를 찾는 방법을 떠올려 보자. 탐색이 끝나면 $i$는 가장 왼쪽의 target을 가리킨다. 따라서 삽입 위치 찾기는 본질적으로 가장 왼쪽 target의 인덱스를 찾는 과정이다.

삽입 위치를 찾는 함수를 이용하여 왼쪽 경계를 찾아 보자. 배열에 target이 없을 수도 있으며, 이때는 다음 두 결과 중 하나가 나올 수 있다.

  • 삽입 위치의 인덱스 $i$가 범위를 벗어난다.
  • 원소 nums[i]가 target과 다르다.

위 두 경우에는 $-1$을 바로 반환하면 된다. 코드는 다음과 같다.

[file]{binary_search_edge}-[class]{}-[func]{binary_search_left_edge}

오른쪽 경계 찾기

가장 오른쪽에 있는 target은 어떻게 찾을까? 가장 직접적인 방법은 코드를 수정하여 nums[m] == target일 때 포인터로 구간을 줄이는 방식을 바꾸는 것이다. 코드는 생략하니, 관심 있는 독자는 직접 구현해 보자.

아래에서는 더 기발한 두 가지 방법을 소개한다.

왼쪽 경계 찾기 재활용

가장 왼쪽 원소를 찾는 함수로 가장 오른쪽 원소도 찾을 수 있다. 구체적으로는 가장 오른쪽 target을 찾는 문제를 가장 왼쪽 target + 1을 찾는 문제로 바꾼다.

아래 그림과 같이 탐색이 끝나면 포인터 $i$는 가장 왼쪽 target + 1(존재한다면)을 가리키고, $j$는 가장 오른쪽 target을 가리킨다. 따라서 $j$를 반환하면 된다.

오른쪽 경계 찾기를 왼쪽 경계 찾기로 변환

반환되는 삽입 위치는 $i$이므로, 여기서 $1$을 빼야 $j$를 얻을 수 있다.

[file]{binary_search_edge}-[class]{}-[func]{binary_search_right_edge}

원소 찾기로 변환

배열에 target이 없으면 최종적으로 $i$는 target보다 큰 첫 번째 원소를, $j$는 target보다 작은 가장 오른쪽 원소를 가리킨다.

따라서 아래 그림과 같이 배열에 없는 원소를 만들어 왼쪽 경계와 오른쪽 경계를 찾을 수 있다.

  • 가장 왼쪽 target 찾기: target - 0.5를 탐색하고 포인터 $i$를 반환하는 것으로 바꿀 수 있다.
  • 가장 오른쪽 target 찾기: target + 0.5를 탐색하고 포인터 $j$를 반환하는 것으로 바꿀 수 있다.

경계 찾기를 원소 찾기로 변환

코드는 생략하며, 다음 두 가지에 주의하자.

  • 주어진 배열에는 소수가 없으므로 값이 같은 경우의 처리는 고려하지 않아도 된다.
  • 이 방법은 소수를 사용하므로 함수의 변수 target을 부동 소수점 타입으로 바꿔야 한다(Python은 수정할 필요가 없다).