티스토리 뷰
문제 설명
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 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 |
입출력 예 설명
예제 #1
- 1번 학생이 2번 학생에게 체육복을 빌려주고, 3번 학생이나 5번 학생이 4번 학생에게 체육복을 빌려주면 학생 5명이 체육수업을 들을 수 있습니다.
예제 #2
- 3번 학생이 2번 학생이나 4번 학생에게 체육복을 빌려주면 학생 4명이 체육수업을 들을 수 있습니다.
풀이 과정
Level 1이라고 하는데 쉽지는 않은 문제입니다.
유형도 ‘그리디’라고는 하는데 잘 모르겠습니다.
그냥 여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다. 이때 이 학생은 체육복을 하나만 도난당했다고 가정하며, 남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없습니다. 이 조건만 잘 염두해 두고 풀면 됩니다. 이걸 어떻게 처리하느냐가 제일 중요한 문제입니다.
처음에는 감을 못 잡다가 set을 사용한다는 힌트를 얻었더니 풀 수 있었습니다. 집합을 사용하면 위의 조건을 교집합을 통해서 구하면 되기 때문입니다.
정답 코드
def solution(n, lost, reserve):
# 교집합을 편하게 구하기 위해 집합을 이용
lost_set = set(lost)
reserve_set = set(reserve)
# 교집합 = 여벌 체육복을 가져온 학생이 체육복을 도난당한 경우
intersection_set = reserve_set.intersection(lost_set)
# 교집합의 경우에는 잃어버려서 체육복을 못 입는 것도, 남에게 빌려줄 수 있는 것도 아니기 때문에 둘 다에서 제거
lost_set -= intersection_set
reserve_set -= intersection_set
# 모든 학생이 lost나 reserve에 포함돼있는 것은 아니기 때문에
# answer의 초기값을 전체 학생 수에서 - 체육복을 잃어버린 학생들로 설정
answer = n - len(lost_set)
# 여분이 있는 학생들 집합을 기준으로 잃어버린 학생들을 확인
for r in reserve_set:
for l in lost_set:
# 잃어버린 학생과 앞 또는 뒷 번호면 -> r의 여분을 l에게 빌려준다
if r == l + 1 or r == l - 1:
# l은 체육복을 받았으니 잃어버린 학생의 집합에서 제거
lost_set.discard(l)
# 체육복 있는 학생 추가
answer += 1
# 현재 보고 있는 r의 체육복 여분은 이제 없으니 탈출해서 다음 r을 확인
break
return answer
문제의 중요 포인트
- 각각을 집합으로 만들어서 교집합을 구한다.
- 교집합이 문제에서 말하는 ‘여벌 체육복을 가져온 학생이 체육복을 도난당한 경우’이다. 이 경우에는 여벌 체육복을 자기 자신이 입어야 하기 때문에 lost에서도, reserve에서도 제외해야 한다.
- answer의 초기값 설정
- lost와 reserve에서 각각 교집합을 제거한 후 그 크기에 맞게 전체 학생 수에서 lost 집합의 크기만큼 뺀 것이 answer의 초기값이 된다.
여분이 있는 학생 집합을 기준으로 잃어버린 학생 집합을 확인한다.
라고 적으려고 했으나, 쓰면서 생각해 보니까 잃어버린 학생 집합을 기준으로(= 외부 for문을 lost_set으로) 해도 상관없을 것 같아서 해 봤더니 맞음. if문 안에서 discard만 내부 for문의 기준 값으로 하면 상관 없이 잘 된다.
이상입니다.
'Algorithm' 카테고리의 다른 글
백준 4948번: 베르트랑 공준 (S2) - Python 풀이 (0) | 2025.03.29 |
---|---|
프로그래머스 Lv.2: 구명보트 - Python 풀이 (0) | 2025.03.28 |
백준 2167번: 2차원 배열의 합 (S5) - Python 풀이 (0) | 2025.03.26 |
프로그래머스 Lv.3: 순위 - Python 풀이 (0) | 2025.03.23 |
백준 14503번: 로봇 청소기 (G5) - Python 풀이 (0) | 2025.03.13 |
- Total
- Today
- Yesterday
- Baekjoon
- dp
- 코딩테스트
- 이분탐색
- 구현
- SQL
- 다이나믹프로그래밍
- ios
- 알고리즘
- 투포인터
- swea
- Python
- 코테준비
- MySQL
- Deque
- 백트래킹
- 그리디
- 큐
- 우선순위큐
- Swift로백준풀기
- 코테
- 힙
- 프로그래머스
- Programmers
- BFS
- 백준
- 자료구조
- 스택
- Swift
- 정렬
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |