데린이 고인물되기

[TIL] 250530 - 프로그래머스 체육복 본문

Algorithm/문제

[TIL] 250530 - 프로그래머스 체육복

데린이 성장 중 2025. 5. 30. 16:08
반응형

문제 설명

점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 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명이 체육수업을 들을 수 있습니다.


나의 답

def solution(n, lost, reserve):
    # 여분있는 애 기준으로 앞에 애가 도난이면 걔면저 주기
    from collections import deque
    # 도난도 당하고 여벌도 있는 학생은 자기 것만 입고 끝
    lost_set = set(lost)
    reserve_set = set(reserve)
    intersect = lost_set.intersection(reserve_set)
    lost_set = lost_set - intersect
    reserve_set = reserve_set - intersect
    
    
    reserve = deque(sorted(reserve_set))
    lost = deque(sorted(lost_set))
    
    
    still_lost = []
    while True:
        if lost:
            fill_candidate = lost.popleft()
            if fill_candidate -1 in reserve:
                reserve.remove(fill_candidate - 1)
                continue
            elif fill_candidate + 1 in reserve:
                reserve.remove(fill_candidate+1)
                continue
            else:
                still_lost.append(fill_candidate)
        else:
            break    
    answer = n - len(still_lost)
    
    return answer
  • lost와 reserve의 교집합을 먼저 제거
  • 그리디하게 앞번호 또는 뒷번호 순으로 빌려줌
  • 체육복 못 입은 학생 수를 전체에서 빼서 정답 도출

🧠회고

  • 리스트 순회할 때 .remove() 사용의 위험성
    • 리스트를 순회하면서 동시에 .remove() 하면 요소가 건너뛰거나 누락될 수 있음
    • 이 때문에 정확한 전처리를 위해 set 기반 연산을 쓰는 방식으로 변경함
    • 처음에 아래와 같이 코드를 짜서 lost를 순회하면서 동시에 lost.remove(i)를 하는 방식을 사용했음. 
      • $ \rightarrow $ 이런 방식은 리스트 구조를 변경하면서 순회하는 것으로, 건너뛰는 요소가 생기는 위험한 방식임
for i in lost:
    if i in reserve:
        lost.remove(i)
        reserve.remove(i)

reserve = deque(sorted(reserve))
lost = deque(sorted(lost))
반응형