코딩테스트 연습에 공개된 문제는 (주)그렙이 저작권을 가지고 있습니다.
(지문 하단에 별도 저작권 표시 문제 제외)
코딩테스트 연습 문제의 지문, 테스트케이스, 풀이 등과 같은 정보는 비상업적, 비영리적 용도로 게시할 수 있습니다.

문제 정보

문제

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 result
[[4,5],[4,8],[10,14],[11,13],[5,12],[3,7],[1,4]] 3

풀이 코드

풀이 코드 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 전체 함수

# 정렬을 위한 함수
def sort_list(list):
    return [list[1], list[0]]

def solution(targets):

    # 앞서있는 target a라는 미사일과 그 뒤에 target b라는 미사일이 있을 때
    # 이들을 한꺼번에 요걱하기 위해선 target b의 시작점이 target a의 사이
    # 즉 target a의 끝지점 이전에 있어야 한다.

    # 정렬하기
    targets.sort(key=sort_list)

    # 끝점에 따라 요격하고
    # 다음 미사일의 시작점이 앞 미사일의 시작점 전이면 함께 요격되는 것으로 여긴다
    count = 0
    last_shoot_point = 0
    
    for target in targets:
        if target[0] >= last_shoot_point:
            count += 1
            last_shoot_point = target[1]
    

    return count

풀이 코드 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 전체 코드
from itertools import combinations

def solution(targets):
    # 변수 선언
    all_target_coord = set()
    shoot_point = []
    shoot_counts = []
    
    # target을 [시작점, 끝점] 에서 [시작점, 시작점 + 1 ... 끝점] 으로 변경
    for i, target in enumerate(targets):
        targets[i] = [x for x in range(target[0], target[1])]
        # all_target_coord에 좌표를 추가
        for point in targets[i]:
            all_target_coord.add(point)

    # 격추할 수 있는 미사일이 2개 이상인 슈팅포인트 리스팅
    for i in all_target_coord:
        count = 0
        for target in targets:
            if i in target:
                count += 1
        if count > 1:
            shoot_point.append(i)
    
    # 미사일을 i 개 발사하는 각 경우의 수에서 모든 미사일을 격추하기 위한 발사 횟수 리스팅
    for i in range(len(shoot_point)):
        for comb in combinations(shoot_point, i+1):
            remove_set = set()
            for shoot in comb:
                for target in targets:
                    if shoot in target:
                        remove_set.add(frozenset(target))
            shoot_counts.append(i + 1 + len(targets) - len(remove_set))

    return min(shoot_counts)

풀이 코드 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 전체 함수
from itertools import combinations

def solution(targets):
    
    # 교집합 구하기
    # 한 번에 격추할 수 있는 경우는?
    # target a와 target b가 있다고 할 때
    # target b의 시작점이 target a의 시작점과 끝점 사이에 있으면 함께 격추할 수 있음
    multikill_list = []

    for i, target_a in enumerate(targets):
        for target_b in targets:
            if target_b[0] in range(target_a[0], target_a[1]):
                try:
                    multikill_list[i].append(target_b)
                except:
                    multikill_list.insert(i, [target_a])
    
    # 미사일을 i 개 발사하는 각 경우의 수에서 모든 미사일을 격추하기 위한 발사 횟수 리스팅
    shoot_counts = []

    for i in range(len(multikill_list)):
        for comb in combinations(multikill_list, i+1):
            remove_set = set()
            multikills = []
            for c in comb:
                multikills.extend(c)
            for target in targets:
                if target in multikills:
                    remove_set.add(frozenset(target))
            shoot_counts.append(i + 1 + len(targets) - len(remove_set))

    return min(shoot_counts)

리뷰

하루에 한 시간 이상씩 3일동안 문제를 풀었다..
시간 초과를 어떻게 해결해야하나 고민이 많았었는데,
결국 다른 사람의 풀이를 참고했다.

다음엔 어려운 문제는 풀기 전 자신만의 언어로 재구성하는 시간을 갖도록 하자.

Reference

https://wikidocs.net/16040
https://armontad-1202.tistory.com/entry/
https://wikidocs.net/16044
https://www.daleseo.com/python-range/
https://wikidocs.net/16041
https://velog.io/@mang0206/