코딩테스트 연습 - 체육복 | 프로그래머스 (programmers.co.kr)
문제 설명
점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 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 |
제출 코드 - 연산 기호 사용하는 경우
def solution(n, lost, reserve):
answer = 0
available = []
idx = 0
# reserve인 사람 중에 lost인 사람은 제외
tmp_lost = lost.copy()
lost = [i for i in lost if i not in reserve]
reserve = [i for i in reserve if i not in tmp_lost]
# 1의 값 가지거나, n값 가지는 경우는 둘 중 한 값만 가지므로 먼저 처리
if 1 in reserve:
try:
lost.pop(lost.index(2))
reserve.pop(reserve.index(1))
except:
reserve.pop(reserve.index(1))
if n in reserve:
try:
lost.pop(lost.index(n-1))
reserve.pop(reserve.index(n))
except:
reserve.pop(reserve.index(n))
while(1):
# reserve로 확인할 값이 더이상 없는 경우 break
if len(reserve) == 0:
break
add_i = reserve[idx] + 1
sub_i = reserve[idx] - 1
if add_i in lost and sub_i in lost:
lost.pop(lost.index(sub_i))
elif add_i not in lost and sub_i in lost:
lost.pop(lost.index(sub_i))
elif add_i in lost and sub_i not in lost:
lost.pop(lost.index(add_i))
reserve.pop(idx)
answer = n - len(lost)
return answer
if __name__ == '__main__':
nums = [5, 5, 3, 5] # 전체 학생의 수
losts = [[2,4], [2,4], [3], [1,2,3]] # 체육복을 도난당한 학생들의 번호가 담긴 배열
reserves = [[1,3,5], [3], [1], [2,3,4]] # 여벌의 체육복을 가져온 학생들의 번호가 담긴 배열
result = [] # 체육수업을 들을 수 있는 학생의 최댓값
for num, lost, reserve in zip(nums, losts, reserves):
result.append(solution(num, lost, reserve))
print(f'result: {result}')
실행 결과
테스트 1 〉 | 통과 (0.01ms, 10.3MB) |
테스트 2 〉 | 통과 (0.01ms, 10.4MB) |
테스트 3 〉 | 통과 (0.02ms, 10.4MB) |
테스트 4 〉 | 통과 (0.01ms, 10.3MB) |
테스트 5 〉 | 통과 (0.02ms, 10.3MB) |
테스트 6 〉 | 통과 (0.01ms, 10.4MB) |
테스트 7 〉 | 통과 (0.03ms, 10.3MB) |
테스트 8 〉 | 통과 (0.02ms, 10.3MB) |
테스트 9 〉 | 통과 (0.01ms, 10.3MB) |
테스트 10 〉 | 통과 (0.02ms, 10.3MB) |
테스트 11 〉 | 통과 (0.01ms, 10.4MB) |
테스트 12 〉 | 통과 (0.01ms, 10.3MB) |
제출 코드 - operator 라이브러리 사용하는 경우
import operator as op
def solution(n, lost, reserve):
answer = 0
available = []
idx = 0
# reserve인 사람 중에 lost인 사람은 제외
tmp_lost = lost.copy()
lost = [i for i in lost if i not in reserve]
reserve = [i for i in reserve if i not in tmp_lost]
# 1의 값 가지거나, n값 가지는 경우는 둘 중 한 값만 가지므로 먼저 처리
if 1 in reserve:
try:
lost.pop(lost.index(2))
reserve.pop(reserve.index(1))
except:
reserve.pop(reserve.index(1))
if n in reserve:
try:
lost.pop(lost.index(n-1))
reserve.pop(reserve.index(n))
except:
reserve.pop(reserve.index(n))
while(1):
# reserve로 확인할 값이 더이상 없는 경우 break
if len(reserve) == 0:
break
add_i = op.add(reserve[idx], 1)
sub_i = op.sub(reserve[idx], 1)
if add_i in lost and sub_i in lost:
lost.pop(lost.index(sub_i))
elif add_i not in lost and sub_i in lost:
lost.pop(lost.index(sub_i))
elif add_i in lost and sub_i not in lost:
lost.pop(lost.index(add_i))
reserve.pop(idx)
answer = n - len(lost)
return answer
if __name__ == '__main__':
nums = [5, 5, 3, 5] # 전체 학생의 수
losts = [[2,4], [2,4], [3], [1,2,3]] # 체육복을 도난당한 학생들의 번호가 담긴 배열
reserves = [[1,3,5], [3], [1], [2,3,4]] # 여벌의 체육복을 가져온 학생들의 번호가 담긴 배열
result = [] # 체육수업을 들을 수 있는 학생의 최댓값
for num, lost, reserve in zip(nums, losts, reserves):
result.append(solution(num, lost, reserve))
print(f'result: {result}')
실행 결과
테스트 1 〉 | 통과 (0.01ms, 10.4MB) |
테스트 2 〉 | 통과 (0.02ms, 10.4MB) |
테스트 3 〉 | 통과 (0.02ms, 10.3MB) |
테스트 4 〉 | 통과 (0.02ms, 10.3MB) |
테스트 5 〉 | 통과 (0.02ms, 10.3MB) |
테스트 6 〉 | 통과 (0.01ms, 10.4MB) |
테스트 7 〉 | 통과 (0.03ms, 10.4MB) |
테스트 8 〉 | 통과 (0.02ms, 10.4MB) |
테스트 9 〉 | 통과 (0.01ms, 10.3MB) |
테스트 10 〉 | 통과 (0.07ms, 10.4MB) |
테스트 11 〉 | 통과 (0.01ms, 10.3MB) |
테스트 12 〉 | 통과 (0.01ms, 10.3MB) |
다른 사람 제출 코드
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
b = r + 1
if f in _lost:
_lost.remove(f)
elif b in _lost:
_lost.remove(b)
return n - len(_lost)
실행 결과
테스트 1 〉 | 통과 (0.01ms, 10.3MB) |
테스트 2 〉 | 통과 (0.01ms, 10.2MB) |
테스트 3 〉 | 통과 (0.01ms, 10.3MB) |
테스트 4 〉 | 통과 (0.01ms, 10.2MB) |
테스트 5 〉 | 통과 (0.01ms, 10.2MB) |
테스트 6 〉 | 통과 (0.01ms, 10.2MB) |
테스트 7 〉 | 통과 (0.02ms, 10.3MB) |
테스트 8 〉 | 통과 (0.01ms, 10.2MB) |
테스트 9 〉 | 통과 (0.00ms, 10.2MB) |
테스트 10 〉 | 통과 (0.02ms, 10.2MB) |
테스트 11 〉 | 통과 (0.01ms, 10.2MB) |
테스트 12 〉 | 통과 (0.01ms, 10.2MB) |
코드 리뷰
다른 사람 코드를 비교했을 때 탐욕법 알고리즘에 따라 먼저 처리해줄 것을 실행해주고 이후 플로우는 비슷했습니다. if문과 list comprehension을 활용하여 reserve와 lost 둘다 해당하는 경우는 먼저 제외해주는 과정은 동일했습니다.
하지만, 그 이후 제 코드 같은 경우 요소가 1이거나 개수에서 가질 수 있는 최대의 수인 경우는 먼저 처리해주었는데 이것도 greedy적인 요소라고 생각했습니다. 하지만 굳이 이렇게 하지 않고도 if문으로 나머지 케이스를 고려해줄 수 잇다는 점을.. 깨달았습니다. 해당 작업 때문에 다른 사람 제출 코드와 실행 시간을 비교했을때 비효율성이 높은 코드임을 확인할 수 있었습니다.
TIL/programmers_greedy.py at master · vg-rlo/TIL (github.com)