본문 바로가기
코딩테스트/문제 풀이

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

by 왕자두 2024. 3. 8.

https://school.programmers.co.kr/learn/courses/30/lessons/42862

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

[문제 이해]

체육복을 도난 당한 학생들이 lost, 여분의 체육복을 가진 학생들이 reserve 리스트로 표현하고 있다. 이 문제에서 가장 중요한 제한 사항은 여분의 체육복을 가진 학생이 체육복을 도난 당했을 때, 더이상 체육복을 빌려줄 수 없기 때문에 lost와 reserve 모두에서 제외되어 도난을 당하지도 않고, 체육복을 빌려주지도 않는 상태가 된다는 것을 이해하는 것이다.

이 외에는 본인보다 앞이나 뒤 번호한테만 체육복을 빌릴 수 있어서 차이가 +1, -1 인 경우만 빌릴 수 있다는 점을 이해하면 문제를 보다 쉽게 풀 수 있다.

 

[문제 풀이]

#1

처음에 제한 사항을 잘못 이해하여 본인이 lost와 reserve에 모두 포함되어있을 때, 원소끼리의 비교를 통해 차가 0인 경우도 answer의 값을 올리는 방식으로 문제를 풀었다. 

import math

def solution(n, lost, reserve):
     answer = n - len(lost) # 이미 체육복이 있는 애들
    
     # lost와 reserve에 겹치는 원소가 있는지 먼저 확인  
    
     for i in lost:
         for j in reserve:
             if abs(i-j) <= 1: 
                 # 도난 당한 애 = 여벌 갖고 있는 애인 경우 abs(i-j) == 0 으로 처리했는데 틀림
                 # 겹치면 먼저 reserve에서 삭제해야함
                 reserve.remove(j)
                 answer += 1
                 break
     return answer

 

그래서 위의 코드와 같이 체육복이 있는 학생을 먼저 answer 값에 저장하고, lost와 reserve를 비교해서 lost의 학생 번호랑 reserve의 학생 번호가 절대값 1 이하로 차이나는 경우, reserve 쪽에서 해당하는 학생을 지워주면서 지워진 학생 번호가 lost 쪽의 학생에게 체육복을 빌려준 상황에 대한 구현을 하려고 했었다.

그러나 겹치는 학생이 있는 경우에 대한 처리를 해주지 않아 첫 번째 제출은 틀렸다.

 

#2

겹치는 학생을 아예 제외하기 위해서는 lost와 reserve 모두에서 겹치는 학생을 제외해야한다. 그러나 list에서 remove 함수를 사용하는 경우, for문 없이 제외하기는 어려웠고, 집합을 사용하기로 했다. 집합을 만들기 위해 set() 함수를 사용하여 각각의 리스트를 집합으로 변환한 후, 차집합을 통해 새로운 변수에 저장한다. 여벌의 옷을 가지고 있는 학생과 도난당한 학생의 번호가 1만큼 차이난다면 빌려줄 수 있기 때문에 lost 리스트에서 삭제한다. 이 과정을 반복한 뒤, 전체 학생 수에서 잃어버렸지만 옷을 빌리지 못한 new_lost 내의 학생들 수를 빼주면 답이 나온다. 최종 코드는 아래와 같다.

 

[최종 코드]

def solution(n, lost, reserve):
    # 겹치는 학생은 사실상 빌려줄 수는 없지만 본인 옷은 있으므로 lost와 reserve에서 모두 제외
    new_lost = set(lost) - set(reserve) # 집합으로 바뀜 (list인 상태에서는 뺄 수 없음) = 차집합
    new_reserve = set(reserve) - set(lost) # 집합으로 바뀜 (list인 상태에서는 뺄 수 없음) = 차집합
    # 만약 여분을 가지고 있는 학생(new_reserve)과
    for i in new_reserve:
        if i-1 in new_lost: # 잃어버린 학생의 번호 차이가 -1만큼 난다면
            new_lost.remove(i-1) # 빌려줄 수 있으므로 해당 학생은 lost(도난당해서 입을 체육복이 없는 학생) 리스트에서 삭제
        elif i+1 in new_lost: # 잃어버린 학생의 번호 차이가 1만큼 난다면
            new_lost.remove(i+1) # 빌려줄 수 있으므로 해당 학생은 lost 리스트에서 삭제
    return n - len(new_lost) # 답은 lost 리스트에 존재하는 학생 수를 전체 학생 수에서 뺀 결과