Programming/Algorithm (Java)

[프로그래머스 level2] 요격 시스템 - Java

jh4dev 2024. 7. 22. 15:28
<목차>

1. 문제
2. 접근 방법
3. 풀이 소스

 

[문제]

A 나라가 B 나라를 침공하였습니다. B 나라의 대부분의 전략 자원은 아이기스 군사 기지에 집중되어 있기 때문에 A 나라는 B 나라의 아이기스 군사 기지에 융단폭격을 가했습니다.
A 나라의 공격에 대항하여 아이기스 군사 기지에서는 무수히 쏟아지는 폭격 미사일들을 요격하려고 합니다. 이곳에는 백발백중을 자랑하는 요격 시스템이 있지만 운용 비용이 상당하기 때문에 미사일을 최소로 사용해서 모든 폭격 미사일을 요격하려 합니다.
A 나라와 B 나라가 싸우고 있는 이 세계는 2 차원 공간으로 이루어져 있습니다. A 나라가 발사한 폭격 미사일은 x 축에 평행한 직선 형태의 모양이며 개구간을 나타내는 정수 쌍 (s, e) 형태로 표현됩니다. B 나라는 특정 x 좌표에서 y 축에 수평이 되도록 미사일을 발사하며, 발사된 미사일은 해당 x 좌표에 걸쳐있는 모든 폭격 미사일을 관통하여 한 번에 요격할 수 있습니다. 단, 개구간 (s, e)로 표현되는 폭격 미사일은 s와 e에서 발사하는 요격 미사일로는 요격할 수 없습니다. 요격 미사일은 실수인 x 좌표에서도 발사할 수 있습니다.
각 폭격 미사일의 x 좌표 범위 목록 targets이 매개변수로 주어질 때, 모든 폭격 미사일을 요격하기 위해 필요한 요격 미사일 수의 최솟값을 return 하도록 solution 함수를 완성해 주세요.


제한 사항

  • 1 ≤ targets의 길이 ≤ 500,000
  • targets의 각 행은 [s,e] 형태입니다.
    • 이는 한 폭격 미사일의 x 좌표 범위를 나타내며, 개구간 (s, e)에서 요격해야 합니다.
    • 0 ≤ s < e ≤ 100,000,000

입출력 예

 

  • targets
    • [[4,5], [4,8], [10,14], [11,13], [5,12], [3,7], [1,4]]
  • result
    • 3

입출력 예 설명

3회 발사로 모두 요격할 수 있음

 


[접근 방법]

1부터 종료 지점을 최소값으로 갱신해나가면서 답을 찾는다.

다음 미사일이 최소 종료지점보다 큰 지점에서 발사되었다면, 이전 미사일들을 요격하고 다시 탐색 해나간다.

 

문제에 제공된 그림을 토대로 먼저 설명해보자면,

  1. [1, 4] 미사일은 4 보다 작은 지점에서 제거가 가능하다.
  2. 그 다음으로 발사 지점이 가까운 [3, 7] 과 비교하면, 3 ~ 4 지점 사이에서 [1, 4] 미사일과 [3, 7] 미사일을 동시에 요격할 수 있다. 다만, 4보다 큰 지점에서는 요격할 수 없다. => 최소 종료지점 : 4
  3. 그 다음으로 발사 지점이 가까운 [4, 5] 의 경우, 발사 지점이 4 이므로 이전 최소 종료지점(4)와 함께 요격할 수 없다.
  4. 따라서, 3.999... 에서 기존 미사일 [1, 4] / [3, 7] 미사일을 요격한다.
  5. 위 과정을 반복하며 탐색
  6. 마지막 미사일까지 탐색을 완료하면, 요격되지 않은 그룹이 남으므로 1을 더해준다.

위 과정은, 시작점 오름차순 정렬 -> 같으면 종료 지점 오름차순 정렬 을 하고 그래프를 그려보면 쉽게 눈에 들어온다.

정렬 후, 타겟 미사일 그래프


 

[풀이 소스]

    import java.util.*;
    class Solution {
        public int solution(int[][] targets) {
            int answer = 0;

            List<int[]> targetList = new ArrayList<int[]>();
            for(int[] target : targets) {
                targetList.add(target);
            }

            //시작점 오름차순 -> 종료점 오름차순 정렬
            targetList.sort((o1, o2) -> {
                int compare = o1[0] - o2[0];
                if(compare == 0) {
                    return o1[1] - o2[1];
                }
                return compare;
            });


            int endPoint 	= targetList.get(0)[1];
            int[] range;

            for(int i = 1; i < targetList.size(); i++) {

                range = targetList.get(i);

                /* 기존 최소 종료지점이, 현 미사일의 시작지점보다 크다면
                *  기존 최소 종료지점과 현 미사일의 종료지점 중 작은 값으로 갱신
                */
                if(range[0] < endPoint) {
                    endPoint 	= Math.min(endPoint, range[1]);

                } else {
                    //기존 최소 종료지점이 현 미사일의 시작지점보다 작다면 발사!
                    //발사
                    answer++;
                    endPoint = range[1];
                    continue;
                }
            }
            //배열의 마지막 미사일에 대한 범위가, 발사 조건은 아니나, 발사하고 끝내야함
            return answer + 1;
        }
    }