Link: https://programmers.co.kr/learn/courses/30/lessons/42862?language=python3
점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다. 체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다.
전체 학생의 수 n, 체육복을 도난당한 학생들의 번호가 담긴 배열 lost, 여벌의 체육복을 가져온 학생들의 번호가 담긴 배열 reserve가 매개변수로 주어질 때, 체육수업을 들을 수 있는 학생의 최댓값을 return 하도록 solution 함수를 작성해주세요.
n lost reserve return
5 [2, 4][1, 3, 5] 5
5 [2, 4][3] 4
3 [3][1] 2
def solution(n, lost, reserve):
# 1. lost와 reserve에 같은 수가 있다면 제거
for x in lost:
if x in reserve:
lost.remove(x)
reserve.remove(x)
# 2
answer = n - len(lost)
# 3
while True:
temp = answer
for x in lost:
if x+1 in reserve and x-1 not in reserve:
answer += 1
reserve.remove(x+1)
lost.remove(x)
elif x-1 in reserve and x+1 not in reserve:
answer += 1
reserve.remove(x-1)
lost.remove(x)
if answer == temp: break
# 4
for x in lost:
if x-1 in reserve:
answer += 1
reserve.remove(x-1)
elif x+1 in reserve:
answer += 1
reserve.remove(x+1)
return answer
우선 잃어버린 사람이 여분으로 체육복을 가지고 있는지부터 판단하는 것이 중요하다. 만약, 여분으로 있는데 잃어버렸다면 그 사람은 그냥 본인의 체육복을 입으면 된다. lost & reserve 리스트에서 제거된다.
정답의 갯수는 잃어버린 사람들이 얼마나 더 많이 입느냐를 구하는 것이기 때문에 answer는 '총인원 - 잃어버린 사람 수'로 시작하면 된다.
while문을 계속해서 반복할 것이다. 만약 앞에 사람에게만 빌릴 수 있다면 그 사람은 앞사람한테서 빌린다. 만약 뒷사람에게만 빌릴 수 있다면, 그 사람은 뒷 사람에게 빌린다. 빌릴 때마다 여분이 있는 사람(reserve)의 리스트가 계속 업데이트 된다. 그렇기 때문에 처음부터 다시 살펴 볼 필요가 있다. 더 이상 빌릴 사람이 없으면 while문을 종료하고 나온다.
이제 잃어버린 사람들 중에 앞사람 혹은 뒷사람에게 빌릴 수 있으면 answer을 증가시켜서 정답을 구한다.
Test Case 7번에 오류가 있다. 분명 알고리즘에 문제가 있어서 놓치고 있는 부분이 있다. 체육복을 빌릴 수 있는 방법 앞과 뒤중 가장 좋은 방법을 택해야 하는데, 그렇지 못해서 정답의 갯수가 차이 나는 것 같다.
*오류발견
오류는 의외로 간단했다. 코드설명 #1번에 여벌의 체육복이 있는 학생이 잃어버렸을경우 다른 사람을 빌려주지 못하고 본인이 해결해야 했는데, 이부분에서 for loop를 돌고있는 lost 함수에서 lost 인덱스들을 remove 하면서 정답이 다르게 나왔다. lost함수를 lost_copy에다가 저장한 후 lost_copy 메소드를 돌면서 lost함수에 아이템들을 제거해주면 문제 없이 해결된다.
#변경사항
lost_copy = lost.copy()
for x in lost_copy:
if x in reserve:
lost.remove(x)
reserve.remove(x)
count = 30
def rec_(k,M,selected,lost,reserve):
temp_lost = lost.copy()
global count
if k == M:
for i in range(0,M):
#만약 0이면 앞쪽 친구가 체육복이 없는지 확인 후 빌려준다.
if selected[i]==0:
if reserve[i]-1 in temp_lost:
temp_lost.remove(reserve[i]-1)
#만약 1이면 뒷쪽 친구가 체육복이 없는지 확인 후 빌려준다.
elif selected[i]==1:
if reserve[i]+1 in temp_lost:
temp_lost.remove(reserve[i]+1)
if len(temp_lost) <= count:
count = len(temp_lost)
else:
for cand in range(0,2):
selected[k] = cand
rec_(k+1,M,selected,lost,reserve)
selected[k] = -1
def solution(n, lost, reserve):
answer = 0
global count
#여벌옷 가져온 학생이 체육복을 잃어버리는 경우
lost_copy = lost.copy()
for i in range(len(lost_copy)):
if lost_copy[i] in reserve:
lost.remove(lost_copy[i])
reserve.remove(lost_copy[i])
print(lost,reserve)
M = len(reserve)
selected = [-1 for _ in range(M)]
rec_(0,M,selected,lost,reserve)
answer = n - count
return answer