[프로그래머스][LV.1] 체육복 | python3

2025. 3. 2. 15:08프로그래머스/LV.1

문제링크:  체육복


문제설명

점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다. 체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다.

전체 학생의 수 n, 체육복을 도난당한 학생들의 번호가 담긴 배열 lost, 여벌의 체육복을 가져온 학생들의 번호가 담긴 배열 reserve가 매개변수로 주어질 때, 체육수업을 들을 수 있는 학생의 최댓값을 return 하도록 solution 함수를 작성해주세요.

 

제한조건

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

 


 

문제풀이

2025.03.16 에 다시 풀어봄,

뭔가 예전보다 덜 깔끔하게 풀린 느낌...인덱스 에러를 처리해야 한다고 계속 생각은 하는데 어딘가 어긋나서 실행시켜보면서  코드를 추가하여 넣음..그리고 이 풀이 말고 분명 다른 풀이도 정리했었는데 기억이 안났다.

나중에는 비슷하게라도 기억해낼 수 있도록 주석을 추가해놨다.

 


 

학생 리스트를 만들어서 체육복을 1개씩 가지고 있다고 가정하여 리스트 원소값을 모두 1로 준다. 학생 번호 = 리스트 인덱스 번호. 학생번호 1번을 리스트 인덱스 1로 만들기 위해 n+1개 만들어줌.

 

lost 리스트를 돌아 체육복을 잃어버린 학생은 리스트 원소값에서 1을 빼준다.

reserve 리스트를 돌아 여분의 체육복을 가지고 있는 학생은 1을 더해준다.

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

이 조건에 부합하게 코드를 짬.

 

인덱스가 넘어가지 않게 검사하고 해당 인덱스 전후로 여벌의 체육복을 가지고 있는 학생이 있는지 검사한 후 있다면 해당 인덱스의 원소값에 1을 더해주고 여벌의 체육복이 있는 학생에게 1을 뺀다.

def solution(n, lost, reserve):
    
    std=[1 for _ in range(n+1)]
    for l in lost:
        std[l]-=1
    for r in reserve:
        std[r]+=1
        
    for idx, cnt in enumerate(std):
        if cnt==0:
            if idx>0 and std[idx-1]==2:
                std[idx]+=1
                std[idx-1]-=1
            elif idx<n+1 and std[idx+1]==2:
                std[idx]+=1
                std[idx+1]-=1
    zero=std.count(0)
    answer=n-zero
            
    return answer

 

2,3,5,9,24,26,27,29 실패로 뜸..

 

인덱스 조건 주는 곳에서 잘 못 쓴거였음

  elif idx<n+1  이 아니라  elif idx<n  으로 써야함.

 

나의코드

def solution(n, lost, reserve):
    answer = 0
    std=[1]*(n+1) # 마지막 답에서 1빼주기. (0인덱스는 빼줘여함)
                  # 0의 갯수를 세었기 때문에 1 안빼줘도 됨
    for i in lost:
        std[i]-=1
    for i in reserve:
        std[i]+=1
    for idx,cnt in enumerate(std):
        # if idx+1==len(std): # 인덱스 에러 피하기 위함
        #     break 
        if cnt==0:
            if std[idx-1]==2: # 인덱스 0번은 무조건 1. (인덱스와 학생 번호를 맞추기 위해 넣은 의미없는 곳이라서)
                std[idx]+=1
                std[idx-1]-=1
            elif idx<n and std[idx+1]==2: # 인덱스 에러 조치 해줘야함.  맨 마지막은 이 조건문을 돌면 안됨
                std[idx]+=1
                std[idx+1]-=1
                
    # answer=std.count(1) - 1 
    # 체육복이 2개인 학생도 체육복을 입을 수 있기때문에 체육복이 없는 애들을 구해서 빼주기
    answer=n-std.count(0)
    return answer

풀이 방법은 유사하나...예전 풀이가 좀 더 깔끔하넹..ㅋㅋㅋ 

그래도 주석을 많이 사용하게 된 건 좋은 발전인 것 같다. 

 

<예전 풀이>

def solution(n, lost, reserve):
    
    std=[1 for _ in range(n+1)]
    for l in lost:
        std[l]-=1
    for r in reserve:
        std[r]+=1
        
    for idx, cnt in enumerate(std):
        if cnt==0:
            if idx>0 and std[idx-1]==2:
                std[idx]+=1
                std[idx-1]-=1
            elif idx<n and std[idx+1]==2:
                std[idx]+=1
                std[idx+1]-=1
    zero=std.count(0)
    answer=n-zero
            
    return answer

 


 

더보기

참고하기

def solution(n, lost, reserve):
    _reserve = [r for r in reserve if r not in lost]
    _lost = [l for l in lost if l not in reserve]
    for r in _reserve:
        f = r - 1 # 2벌 있는 학생의 앞 번호
        b = r + 1 # 2벌 있는 학생의 뒷 번호
        if f in _lost:
            _lost.remove(f)
        elif b in _lost:
            _lost.remove(b)
        # 2벌 가지고 있는 학생 앞 뒤 를 살펴 체육복이 없는 친구에게 체육복을 빌러줌 => _lost에서 삭제
        # _lost에 남아있는 애들은 체육복을 빌리지 못한 학생들
    return n - len(_lost)

 

reserve와 lost 동시에 있는 학생은 빼서 진짜 lost와 reserve의 리스트를 새로 만들어 낸다.

여벌이 있는 학생의 전 후 학생이 lost에 있는지 확인하여 있으면 lost에서 지운다. 

최종적으로 체육복이 없는 학생의 수를 n에서 빼면 됨.

 

지금은 18번 20번에서 에러가 난다고 하는데 _reserve값을 정렬해주면 통과된다고 함.

=> 통과됨.

 

앞에서부터 바꿔야 효율적이기 때문인 것 같음