[Algorithm] 이분 탐색 유형 모음

2025. 3. 4. 22:36·Algorithm
728x90
반응형

Lower Bound

Lower Bound는 정렬된 배열에서 특정 값(= 키 값) 이상이 처음으로 나타나는 위치를 찾는다.
=> 즉, 주어진 값 이상인 첫 번째 원소의 인덱스를 반환한다.

 

특징

  • 중복된 값이 존재할 때, 가장 처음 등장하는 위치를 반환
  • 값이 존재하지 않으면 삽입될 첫 번째 위치를 반환
import java.util.Arrays;

public class LowerBoundExample {
    public static void main(String[] args) {
        int[] arr = {1, 2, 4, 4, 4, 7, 9};
        int target = 4;
        int index = lowerBound(arr, target);
        System.out.println("Lower Bound Index: " + index);
    }

    static int lowerBound(int[] arr, int key) {
        int left = 0, right = arr.length;
        while (left < right) {
            int mid = (left + right) / 2;
            if (arr[mid] >= key) right = mid;
            else left = mid + 1;
        }
        return left;
    }
}
Lower Bound Index: 2

Upper Bound

Upper Bound는 정렬된 배열에서 특정 값(= 키 값)보다 큰 값이 처음 나타나는 위치를 찾는다.
=> 즉, 주어진 값보다 큰 첫 번째 원소의 인덱스를 반환

 

특징

  • 중복된 값이 존재할 때, 가장 마지막을 지나치는 위치를 반환
  • 값이 존재하지 않으면 배열의 길이를 반환
public class UpperBoundExample {
    public static void main(String[] args) {
        int[] arr = {1, 2, 4, 4, 4, 7, 9};
        int target = 4;
        int index = upperBound(arr, target);
        System.out.println("Upper Bound Index: " + index);
    }

    static int upperBound(int[] arr, int key) {
        int left = 0, right = arr.length;
        while (left < right) {
            int mid = (left + right) / 2;
            if (arr[mid] > key) right = mid;
            else left = mid + 1;
        }
        return left;
    }
}
Upper Bound Index: 5

 

만약 중복된 값이 존재할 때, 그 중 가장 마지막 위치를 찾고 싶다면?
=> upper bound index - 1을 해주면 된다.
=> upperBound의 반환 값에서 left가 아닌 left - 1을 해주자.


Parametric Search

Parametric Search는 최적화 문제를 '예/아니오' 결정 문제로 변환하여 해결하는 기법이다.
이분 탐색을 사용해 가능한 범위에서 최적의 해를 찾을 수 있다.

 

사용 예시: 예산 배분, 최소/최대 작업 시간, 나무 자르기 문제 등

 

중요 포인트

  • left, right 값의 범위
  • key 값이 무엇인지 설정하기
  • Upper Bound 문제인지, Lower Bound 문제인지 확인

예시 문제 1: 나무 자르기

백준 2805번: 나무 자르기(S2)

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());

        long[] trees = new long[N];
        st = new StringTokenizer(br.readLine());
        long right = -1;
        for (int i = 0; i < N; i++) {
            trees[i] = Long.parseLong(st.nextToken());
            right = Math.max(right, trees[i]);
        }

        long left = 0;
        long mid;

        while (left < right) {
            mid = (left + right) / 2;

            // 얻을 수 있는 총 나무 높이 구하기
            long ret = 0;
            for (long tree : trees) {
                if(tree > mid) ret += (tree - mid);
            }

            // 최대 높이를 구하는 것이므로 Upper Bound로 해결
            // Upper Bound: 최초로 필요 길이(M)을 넘는 값
            if(ret < M) right = mid; // 부족하면 낮추기
            else left = mid + 1; // 충분히 가져갈 수 있으면 더 높이 잘라보기 
        }

        System.out.println(left - 1); // Upper Bound는 '최초로 필요 길이(M)을 넘는 값'이므로, 그 이전 값인 left-1을 출력
    }
}

예시 문제 2: 공유기 설치

백준 2110번: 공유기 설치(G4)

public class Main {

    static int[] house;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        int C = Integer.parseInt(st.nextToken());

        house = new int[N];

        for (int i = 0; i < N; i++) {
            house[i] = Integer.parseInt(br.readLine());
        }

        Arrays.sort(house);

        int left = 1, right = house[N - 1] - house[0] + 1, mid = 0;

        while (left < right) {
            mid = (left + right) / 2;

			// 설치 가능한 공유기 수가 최대가 되도록 하는 값을 구하고 싶음
            // -> Upper Bound
			// 최소 거리가 mid일 때, 설치가능한 공유기 수가 C보다 작다면
            if (getInstallableCnt(mid) < C) right = mid; // 범위를 줄임
            else left = mid + 1; // 크거나 같다면 범위를 늘림
        }

        System.out.println(left - 1);
    }

	// 최소 거리가 distance일 때, 설치 가능한 공유기의 수
    private static int getInstallableCnt(int distance) {
        int count = 1;
        int lastLocate = house[0]; // 반드시 첫 집에는 공유기를 둔다고 가정

        for (int i = 1; i < house.length; i++) {
            if (house[i] - lastLocate >= distance) {
                ++count;
                lastLocate = house[i];
            }
        }

        return count;
    }
}
728x90
반응형

'Algorithm' 카테고리의 다른 글

[Algorithm] 그래프와 순회 유형 모음  (0) 2025.03.05
[Algorithm] 동적 프로그래밍(Dynamic Programming) 기초 유형 모음  (0) 2025.02.26
[Algorithm] 완전 탐색(Brute Force) 유형 모음 feat. Java  (0) 2025.02.18
[Algorithm] 정수론  (0) 2025.01.03
[Algorithm] 최소 스패닝 트리(MST) 문제  (2) 2024.12.13
'Algorithm' 카테고리의 다른 글
  • [Algorithm] 그래프와 순회 유형 모음
  • [Algorithm] 동적 프로그래밍(Dynamic Programming) 기초 유형 모음
  • [Algorithm] 완전 탐색(Brute Force) 유형 모음 feat. Java
  • [Algorithm] 정수론
mxruhxn
mxruhxn
소소하게 개발 공부 기록하기
    반응형
    250x250
  • mxruhxn
    maruhxn
    mxruhxn
  • 전체
    오늘
    어제
    • 분류 전체보기 (150)
      • Java (21)
      • Spring (4)
      • Database (13)
      • Operating Syste.. (1)
      • Computer Archit.. (0)
      • Network (24)
      • Data Structure (6)
      • Algorithm (11)
      • Data Infra (7)
      • DevOps (12)
      • ETC (27)
      • Project (21)
      • Book (1)
      • Look Back (1)
  • 블로그 메뉴

    • 링크

      • Github
    • 공지사항

    • 인기 글

    • 태그

    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.0
    mxruhxn
    [Algorithm] 이분 탐색 유형 모음
    상단으로

    티스토리툴바