[백준] 3020: 개똥벌레 - JAVA

https://www.acmicpc.net/problem/3020

풀이

석순과 종유석이 번갈아 나오는 동굴을 장애물을 파괴하면서 지나가야한다.

높이별로 만나는 장애물의 개수를 세어 최솟값을 찾는 문제이다.

처음에 누적합으로 문제를 풀었고, 이분 탐색으로 푸는 방법이 있다고하여 찾아보았다.

  • 이분 탐색

    이분 탐색으로 풀기 위해서는 석순과 종유석을 따로 배열에 담아준다.

    bottom배열에 석순을, top배열에 종유석을 담았다.

    이분탐색을 위해 배열을 정렬한 뒤 1부터 H까지 높이을 key로 하여 이분탐색을 진행한다.

    석순과 종유석을 각각 진행하여 해당 key값(key값보다 크거나 같은 첫번째 인덱스)을 찾아 arr.length - rigth을 반환하면 해당 구간의 장애물의 개수를 구할 수 있다.

  • 누적 합

    누적 합으로 풀기 위해 우선 높이를 length로 하는 배열을 만들고 입력받으면서 [석순의 높이]를 인덱스로 하는 값을 증가시키고,

    종유석의 경우 [높이 - 종유석의 높이]의 값을 감소, [높이]의 값을 증가시킨다.

    입력 후 H부터 하향식 탐색하며 arr[i] += arr[i + 1]하여 누적 합해준다.

    누적 합이 된 배열을 탐색하여 최솟값을 찾는다.


이분 탐색

메모리: 34068KB

시간: 616ms

언어: Java 11

코드

import java.io.*;
import java.util.*;

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 H = Integer.parseInt(st.nextToken());

        int[] bottom = new int[N / 2];
        int[] top = new int[N / 2];
        for (int i = 0; i < N / 2; i++) {
            bottom[i] = Integer.parseInt(br.readLine());
            top[i] = Integer.parseInt(br.readLine());
        }

        Arrays.sort(bottom);
        Arrays.sort(top);

        int min = Integer.MAX_VALUE;
        int cnt = 0;
        for (int i = 1; i < H + 1; i++) {
            int tmp = binarySearch(0, N / 2, i, bottom) + binarySearch(0, N / 2, H - i + 1, top);

            if (tmp < min) {
                min = tmp;
                cnt = 1;
            } else if (tmp == min) {
                cnt++;
            }
        }

        System.out.println(min + " " + cnt);
    }

    private static int binarySearch(int left, int right, int key, int[] arr) {
        while (left < right) {
            int mid = (left + right) / 2;

            if (arr[mid] >= key) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }

        return arr.length - right;
    }

}

누적 합

메모리: 29272KB

시간: 320ms

언어: Java 11

코드

import java.io.*;
import java.util.*;

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 H = Integer.parseInt(st.nextToken());

        int[] arr = new int[H + 1];
        for (int i = 0; i < N; i++) {
            int a = Integer.parseInt(br.readLine());
            if (i % 2 == 0) {
                arr[a]++;
            } else {
                arr[H - a]--;
                arr[H]++;
            }
        }

        for (int i = H - 1; i > 0; i--) {
            arr[i] += arr[i + 1];
        }

        int min = Integer.MAX_VALUE;
        int cnt = 0;
        for (int i = 1; i < H + 1; i++) {
            if (arr[i] < min) {
                min = arr[i];
                cnt = 1;
            } else if (arr[i] == min) {
                cnt++;
            }
        }

        System.out.println(min + " " + cnt);
    }

}