[Programmers] 기능개발
프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100% 일 때 서비스에 반영할 수 있습니다.
또, 각 기능의 개발속도는 모두 다르기 때문에 뒤에 있는 기능이 앞에 있는 기능보다 먼저 개발될 수 있고, 이때 뒤에 있는 기능은 앞에 있는 기능이 배포될 때 함께 배포됩니다.
먼저 배포되어야 하는 순서대로 작업의 진도가 적힌 정수 배열 progresses와 각 작업의 개발 속도가 적힌 정수 배열 speeds가 주어질 때 각 배포마다 몇 개의 기능이 배포되는지를 return 하도록 solution 함수를 완성하세요.
개요
문제가 Stack/Queue라는 카테고리로 분류되어 있어서 그런지 최대한 Stack과 Queue라는 개념을 활용해서 풀어보려고 했으나 정작 이용한 개념은 Stack 밖에 없었다. 초반 로직을 잡아두고 제출했는데 1,2,4,5번의 TestCase에서 실패가 떴다.
"질문하기"에서 힌트를 얻어 풀 수 있었으며 문제의 자세한 설명은 프로그래머스에 가서 확인하도록 하자.
여기서는 어떤 식으로 풀었는지만 남기려고 한다.
풀이 과정
문제에서는 작업진도(progresses)와 작업 속도(speeds)라는 배열이 주어진다. 문제 설명을 읽어보면 이 작업 진도와 작업 속도를 통해 알아낼 수 있는 건 "작업이 완료되기까지의 남은 날"이다. 프로그래머스의 문제 설명에도 나와있지만 적어보자면 다음과 같다.
progress = [93, 30, 55]
speeds = [1, 30, 5]
"작업이 완료되기까지의 남은 날"은 다음과 같다.
remain_day = [7 ,2 ,9]
사실 이 "작업이 완료되기까지의 남은 날"을 잘 취합해서 return 하는 게 문제 풀이의 핵심이라고 생각했다. 이 배열을 문제에서 요구하는 형태로 리턴하기 위해 Stack을 통해 다음과 같은 순서를 생각했다.
1. stack의 초기값을 7로 설정하고 이를 start_day라 생각하자.
2. 이후 들어오는 value와 stack의 초기값을 비교하여 value가 더 작다면 stack에 삽입하자.
3. 만약 들어오는 value가 start_day라 지정했던 값보다 크다면 stack에 존재하는 값의 길이를 answer에 append 하고 stack을 비운뒤 새 value를 stack의 초기값으로 지정하고 start_day를 갱신하자.
이 순서대로 로직을 구성하고 코드를 작성했다.
첫 번째 시도
아래 코드는 제일 처음 작성한 코드이다.
def solution(progresses, speeds):
days = []
for p, s in zip(progresses, speeds):
day, remainder = divmod((100 - p), s)
if remainder != 0:
day += 1
days.append(day)
answer = []
init = [days[0]]
for i, v in enumerate(days[1:], start=0):
if init[0] > v:
init.append(v)
if init[0] < v:
answer.append(len(init))
init = [v]
answer.append(len(init))
return answer
사실 위 코드는 개요에서 언급했듯이 1,2,4,5에 대한 TestCase를 통과하지 못했다. "질문하기"을 통해서 테스트 케이스를 참고했는데 아래 케이스에 대해서 실패했다는 것을 알 수 있었다.
progresses = [99,99,99]
speeds = [1,1,1]
남은 작업 진행속도(speeds)가 모두 같은 경우에 대해 생각하지 못했다는 것을 알 수 있었다.
두 번째 시도
어떤 경우에는 테스트 케이스를 알아도 코드를 고치기 어려운 경우가 더러 있는데 이번에는 한 줄만 변경하면 되었다.
def solution(progresses, speeds):
days = []
for p, s in zip(progresses, speeds):
day, remainder = divmod((100 - p), s)
if remainder != 0:
day += 1
days.append(day)
answer = []
init = [days[0]]
for i, v in enumerate(days[1:], start=0):
if init[0] >= v: # (변경) 남아있는 값이 다 같은 경우
init.append(v)
if init[0] < v:
answer.append(len(init))
init = [v]
answer.append(len(init))
return answer
결과
제출한 결과는 다음과 같다.
사실 날짜를 구하는 과정에서 divmod를 사용하기 떄문에 '0'이 들어오면 ZeroDivisionError가 나기 때문에 완벽하다고는 볼 수 없을 것 같지만 통과는 되었으니 나름 흡족하다.