본문 바로가기
프로그래머스/고득점 Kit

[프로그래머스] 체육복 - Python / 파이썬

by yewonnie 2023. 2. 16.

문제 설명 

점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다. 체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다.
전체 학생의 수 n, 체육복을 도난당한 학생들의 번호가 담긴 배열 lost, 여벌의 체육복을 가져온 학생들의 번호가 담긴 배열 reserve가 매개변수로 주어질 때, 체육수업을 들을 수 있는 학생의 최댓값을 return 하도록 solution 함수를 작성해주세요.

제한 사항 

- 전체 학생의 수는 2명 이상 30명 이하입니다.
- 체육복을 도난당한 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.
- 여벌의 체육복을 가져온 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.
- 여벌 체육복이 있는 학생만 다른 학생에게 체육복을 빌려줄 수 있습니다.
- 여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다. 이때 이 학생은 체육복을 하나만 도난당했다고 가정하며, 남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없습니다.

입출력 예 

n lost reserve return
5 [2, 4] [1, 3, 5] 5
5 [2, 4] [3] 4
3 [3] [1] 2

문제 풀이

체육복 문제는 제한 사항을 잘 읽어야 하고, 문제를 해결할 수 있는 아이디어를 떠올리는 것이 중요했다.

 

여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다. 이때 이 학생은 체육복을 하나만 도난당했다고 가정하며, 남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없습니다.

 

위에 제시된 제한사항을 제대로 파악해야만 문제를 해결하기 전 lost와 reserve를 알맞게 설정해줄 수 있다. 

체육복을 빌려줄 수 있는 사람이 도난을 당했다면 체육복을 빌려주지 못하게 된다. 

즉, reserve에 있는 학생이 lost에도 존재한다면 체육복을 빌려주지 못하므로 더이상 reserve 목록에 있을 수 없게된다.

따라서 lost에 존재하는 학생을 reserve에서 모두 빼줘야한다. 

이와 마찬가지로, 도난 당한 사람 중에 빌려 줄 수 있는 사람이 있다면 체육복 한개가 있으므로 체육복을 빌리지 않아도 된다. 따라서 reserve에 존재하는 학생을 lost에서 모두 빼줘야한다. 

 

이 과정을 거치게 되면 정말로 체육복을 도난당한 사람과 정말로 빌려 줄 수 있는 사람만이 목록에 남게된다. 

이제 체육복을 빌려 줄 수 있는 학생들은 자신의 양 옆 번호 학생에게만 체육복을 빌려줄 수 있는데 

이때, 왼쪽을 먼저 탐색해야만 한다. 

n lost reserve return
5 [2, 4] [3, 5] 5

위와 같은 조건에서 3번 학생은 2, 4 학생에게

5번 학생은 4번 학생에게 체육복을 빌려 줄 수 있는데 

만약 3번 학생이 4번 학생에게 체육복을 빌려주면 2번 학생은 체육복을 빌릴 수 없게된다.

따라서, 최대한 많은 학생이 체육복을 빌리려면 왼쪽부터 탐색해야하는 것을 알 수 있다. 

 

이처럼 왼쪽 학생부터 탐색하며 체육복을 도난 당한 학생에게 체육복을 빌려주고 

체육복을 빌렸다면 lost 목록에서 제거해준다. 

최종적으로 총 학생 수 n에서 lost 목록에 남아있는 학생의 수를 빼주면 답을 구할 수 있다. 


My Code

def solution(n, lost, reserve):

	set_reserve = set(reserve) - set(lost)
    set_lost = set(lost) - set(reserve)

    for i in set_reserve:
        if i-1 in set_lost:
            set_lost.remove(i-1)
        elif i+1 in set_lost:
            set_lost.remove(i+1)

    return n - len(set_lost)

댓글