알고리즘/99Club

99클럽 코테 스터디 14일차 TIL + Java Algorithm

dami97 2024. 8. 4. 18:33
반응형

소개

  • 알고리즘 스터디를 참여하며 작성하는 TIL입니다.
  • TIL이란? 'Today I Learned'의 약자로, 한국어로 번역하면 '오늘 내가 배운 것'이란 의미입니다.
  • 제가 오늘 하루 배운 것 혹은 경험하고 느낀 것들을 기록하고 회고하는 습관을 기르기 위한 글입니다.

 

문제 & 키워드

  • 프로그래머스 - 징검다리 (문제 링크)
  • 이진 탐색
  • 최적화 문제

문제 설명

출발지점부터 distance만큼 떨어진 곳에 도착지점이 있습니다. 그리고 그사이에는 바위들이 놓여있습니다. 바위 중 몇 개를 제거하려고 합니다.

예를 들어, 도착지점이 25만큼 떨어져 있고, 바위가 [2, 14, 11, 21, 17] 지점에 놓여있을 때 바위 2개를 제거하면 출발지점, 도착지점, 바위 간의 거리가 아래와 같습니다.

 

제거한 바위의 위치 각 바위 사이의 거리 거리의 최솟값
[21, 17] [2, 9, 3, 11] 2
[2, 21] [11, 3, 3, 8] 3
[2, 11] [14, 3, 4, 4] 3
[11, 21] [2, 12, 3, 8] 2
[2, 14] [11, 6, 4, 4] 4

위에서 구한 거리의 최솟값 중에 가장 큰 값은 4입니다.

출발지점부터 도착지점까지의 거리 distance, 바위들이 있는 위치를 담은 배열 rocks, 제거할 바위의 수 n이 매개변수로 주어질 때, 바위를 n개 제거한 뒤 각 지점 사이의 거리의 최솟값 중에 가장 큰 값을 return 하도록 solution 함수를 작성해주세요.

제한사항

  • 도착지점까지의 거리 distance는 1 이상 1,000,000,000 이하입니다.
  • 바위는 1개 이상 50,000개 이하가 있습니다.
  • n은 1 이상 바위의 개수 이하입니다.

입출력 예

distance rocks n return

25 [2, 14, 11, 21, 17] 2 4

입출력 예 설명

문제에 나온 예와 같습니다.


문제 접근

이 문제는 주어진 바위들을 제거하여 각 지점 사이의 거리의 최솟값을 최대화하는 문제입니다. 이를 해결하기 위해 이진 탐색을 활용할 수 있습니다.

  1. 바위 정렬
    • 주어진 바위의 위치를 오름차순으로 정렬합니다.
  2. 이진 탐색 범위 설정
    • 최소 거리 left는 0으로 설정하고, 최대 거리 right는 도착지점까지의 거리로 설정합니다.
  3. 중간값 계산
    • 이진 탐색의 중간값을 계산하여, 해당 값이 각 지점 사이의 거리의 최솟값으로 설정할 수 있는지 확인합니다.
  4. 거리 검증
    • 바위를 순서대로 확인하면서, 중간값보다 작은 거리를 유지하기 위해 필요한 제거된 바위의 수를 계산합니다.
  5. 최적화된 거리 갱신
    • 제거된 바위의 수가 조건을 만족하는지 확인하고, 만족하면 최적의 거리를 갱신하며 탐색 범위를 조정합니다.

 

풀이

import java.util.*;

class Solution {
    public int solution(int distance, int[] rocks, int n) {
        // 예외 처리
        if (rocks.length == n) return distance;

        // 1. 바위 정렬
        Arrays.sort(rocks);

        // 각 지점 사이의 거리 계산
        int[] d = new int[rocks.length + 1];
        d[0] = rocks[0];
        d[d.length - 1] = distance - rocks[rocks.length - 1];
        for (int i = 1; i < rocks.length; i++) {
            d[i] = rocks[i] - rocks[i - 1];
        }

        // 2. 이진 탐색 범위 설정
        int left = 0;
        int right = distance;

        // 3. 이진 탐색 수행
        while (left < right) {
            int mid = (left + right) / 2;
            int removedStone = 0;
            int cur = 0;

            // 4. 거리 검증
            for (int i = 0; i < d.length; i++) {
                cur += d[i];
                if (cur < mid) {
                    removedStone++;
                } else {
                    cur = 0;
                }
            }

            // 5. 최적화된 거리 갱신
            if (removedStone < n) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }

        return left - 1;
    }
}

 

풀이 설명

  1. 바위 정렬
    • 주어진 바위의 위치를 오름차순으로 정렬합니다.
  2. 이진 탐색 범위 설정
    • 최소 거리 left를 0으로 설정하고, 최대 거리 right를 도착지점까지의 거리로 설정합니다.
  3. 이진 탐색 수행
    • left가 right보다 작을 때까지 이진 탐색을 수행합니다.
    • 중간값 mid를 계산하고, 이 값을 기준으로 각 지점 사이의 거리의 최솟값을 설정합니다.
  4. 거리 검증
    • 각 바위 사이의 거리를 합산하면서, 중간값보다 작은 거리를 유지하기 위해 필요한 제거된 바위의 수를 계산합니다.
    • 제거된 바위의 수가 n보다 작으면 left를 mid + 1로 설정하고, 그렇지 않으면 right를 mid로 설정합니다.
  5. 최적화된 거리 갱신
    • 탐색 범위를 조정하여 가능한 최적의 거리를 찾습니다.
    • 최종적으로 left - 1을 반환하여 바위를 제거한 뒤 각 지점 사이의 거리의 최솟값 중 가장 큰 값을 반환합니다.

 


 

마무리하며

  • 이번 문제를 통해 이진 탐색을 활용한 최적화 문제 해결 방법을 익힐 수 있었습니다.
  • 문제를 해결하기 위해 바위 간의 거리를 계산하고 조건에 맞게 탐색 범위를 조정하는 과정이 중요함을 배웠습니다.