Python/Coding Test 기록

[프로그래머스/LV.1] 체육복 (그리디)

yerinn 2022. 1. 29. 16:18

문제 설명

점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 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):
    std=[1]*n
    
    for i in lost:
        std[i-1]-=1
    
    for j in reserve:
        std[j-1]+=1
    
    for k in range(1,n-1):
        if std[k]==0:
            if std[k+1]==2:
                std[k]=1
                std[k+1]=1
            else:
                if std[k-1]==2:
                    std[k]=1
                    std[k-1]=1
    
    if std[-1]==0 & std[-2]==2:   # 마지막학생 체육복 없고 마지막 직전 학생 2벌일때
        std[-1]=1
        std[-2]=1
    
    answer=std.count(1)+std.count(2)
        
    return answer

웨않되...?

ㅠㅠ

 

학생 배열을 만들어 모두 0 값으로 초기화한뒤

lost에 속한 경우 -1, reserve에 속한 경우 +1

 

for문을 돌려 n번째 학생이 체육복이 없고(0)

n+1번째 또는 n-1 학생이 여벌 체육복이 있을때(2)

 

n+1 또는 n-1 이 n 에게 체육복을 빌려주고 각각 1로 값 셋팅

 

단 맨 앞과 맨 마지막 친구들은 별도의 case로 빼서

if 문으로 경우를 따져주었다.

 

마지막으로 배열값이 1 or 2 인 학생들의 수를 구함.

 

머리로는 맞는데 ㅠㅠ 틀렸다니까 넘 답답시럽다..

 

 

다른사람 풀이 (출처: https://jokerldg.github.io/algorithm/2021/04/03/gym-suit.html)

def solution(n, lost, reserve):
    reserve_set = set(reserve)-set(lost)  # 도난x 여벌옷o 학생들 -> 빌려줄 수 있음
    lost_set = set(lost)-set(reserve)   # 도난o 여벌옷x 학생들 -> 빌려 받아야 함
    
    for i in reserve_set: # 옷 빌려줄 수 있는 학생들 i
        
        if i-1 in lost_set:   # i 앞 학생이 i에게 빌려받음
            lost_set.remove(i-1)  # i-1 은 수업참가 가능하니 remove
        
        elif i+1 in lost_set: # i 뒤 학생이 i에게 빌려받음
            lost_set.remove(i+1) # i+1 도 수업참가 가능하니 remove
    
    return n-len(lost_set)  # 총 학생 - 수업참가 못하는 학생수

생각치도 못하게 set 자료형으로 문제를 푸셨다.

set 자료형은 중복값을 제거할때 유용하게 쓰인다.

대략적으로 보니 (전체학생 수 - 여벌 옷도 없고 도난도 당한 학생 수)로 정답을 구했다. 

 

문제의 제한사항에 힌트가 많이 있다 하는데,

lost와 reserve배열에는 각 배열 내 중복되는 값이 없다는 것이다.

 

때문에, set 자료형으로 변환을 해도 삭제되는 값 없이

- 연산을 이용해 차집합을 구해 두 리스트에서 중복되는 값*을 제거 할 수 있다.

*lost 와 동시에 reserve 에 속하는 친구들은 체육복이 하나이니 체육복을 빌려줄 수 없다.