프로그래머스 ‘무지의 먹방 라이브’

조배·2022년 2월 26일
0

Road to Coding test

목록 보기
17/31
post-thumbnail

문제 링크 및 문제 내용

코딩테스트 연습 - 무지의 먹방 라이브 | 프로그래머스 (programmers.co.kr)

문제 설명

무지의 먹방 라이브

  • 효율성 테스트에 부분 점수가 있는 문제입니다.

평소 식욕이 왕성한 무지는 자신의 재능을 뽐내고 싶어 졌고 고민 끝에 카카오 TV 라이브로 방송을 하기로 마음먹었다.

https://grepp-programmers.s3.amazonaws.com/files/production/10f4f72c93/1d932bfc-8082-4b7e-b30d-ab46bf71a9f2.png

그냥 먹방을 하면 다른 방송과 차별성이 없기 때문에 무지는 아래와 같이 독특한 방식을 생각해냈다.

회전판에 먹어야 할 N 개의 음식이 있다.각 음식에는 1부터 N 까지 번호가 붙어있으며, 각 음식을 섭취하는데 일정 시간이 소요된다.무지는 다음과 같은 방법으로 음식을 섭취한다.

  • 무지는 1번 음식부터 먹기 시작하며, 회전판은 번호가 증가하는 순서대로 음식을 무지 앞으로 가져다 놓는다.
  • 마지막 번호의 음식을 섭취한 후에는 회전판에 의해 다시 1번 음식이 무지 앞으로 온다.
  • 무지는 음식 하나를 1초 동안 섭취한 후 남은 음식은 그대로 두고, 다음 음식을 섭취한다.
    • 다음 음식이란, 아직 남은 음식 중 다음으로 섭취해야 할 가장 가까운 번호의 음식을 말한다.
  • 회전판이 다음 음식을 무지 앞으로 가져오는데 걸리는 시간은 없다고 가정한다.

무지가 먹방을 시작한 지 K 초 후에 네트워크 장애로 인해 방송이 잠시 중단되었다.무지는 네트워크 정상화 후 다시 방송을 이어갈 때, 몇 번 음식부터 섭취해야 하는지를 알고자 한다.각 음식을 모두 먹는데 필요한 시간이 담겨있는 배열 food_times, 네트워크 장애가 발생한 시간 K 초가 매개변수로 주어질 때 몇 번 음식부터 다시 섭취하면 되는지 return 하도록 solution 함수를 완성하라.

제한사항

  • food_times 는 각 음식을 모두 먹는데 필요한 시간이 음식의 번호 순서대로 들어있는 배열이다.
  • k 는 방송이 중단된 시간을 나타낸다.
  • 만약 더 섭취해야 할 음식이 없다면 1을 반환하면 된다.

정확성 테스트 제한 사항

  • food_times 의 길이는 1 이상 2,000 이하이다.
  • food_times 의 원소는 1 이상 1,000 이하의 자연수이다.
  • k는 1 이상 2,000,000 이하의 자연수이다.

효율성 테스트 제한 사항

  • food_times 의 길이는 1 이상 200,000 이하이다.
  • food_times 의 원소는 1 이상 100,000,000 이하의 자연수이다.
  • k는 1 이상 2 x 10^13 이하의 자연수이다.

입출력 예

입출력 예 설명

입출력 예 #1

  • 0~1초 동안에 1번 음식을 섭취한다. 남은 시간은 [2,1,2] 이다.
  • 1~2초 동안 2번 음식을 섭취한다. 남은 시간은 [2,0,2] 이다.
  • 2~3초 동안 3번 음식을 섭취한다. 남은 시간은 [2,0,1] 이다.
  • 3~4초 동안 1번 음식을 섭취한다. 남은 시간은 [1,0,1] 이다.
  • 4~5초 동안 (2번 음식은 다 먹었으므로) 3번 음식을 섭취한다. 남은 시간은 [1,0,0] 이다.
  • 5초에서 네트워크 장애가 발생했다. 1번 음식을 섭취해야 할 때 중단되었으므로, 장애 복구 후에 1번 음식부터 다시 먹기 시작하면 된다.

풀이 코드

# 프로그래머스 '무지의 먹방라이브'
# 힙 구조 라이브러리
import heapq

def solution(food_times, k):
    # answer를 못 구할 경우 -1 
    answer = -1
    # 힙 리스트
    hq = []
    # 힙리스트에 (섭취 시간, 순번)을 넣어준다.
    for i in range(len(food_times)):
        heapq.heappush(hq, (food_times[i], i+1))      
    length = len(hq)     # 음식 갯수 (한 사이클) 
    pre = 0  # 전 음식의 섭취 시간
    while hq:   # 리스트가 빌때까지
        # 가장 적은 섭취시간과 전 음식시간의 섭취시간을 빼주고, 음식 갯수를 곱해준다.
        diff = (hq[0][0] - pre) * length
        # 한사이클의 음식량을 빼줄 diff가 k보다 작거나 같으면 빼준다.
        if diff <= k:
            k -= diff
            # 한사이클을 돌렸기 때문에 해당 음식은 다먹었으니 제외 시킨다.
            length -= 1
            # 음식을 리스트에서 제외시키고, 해당 순서의 섭취시간을 변수에 업데이트 해준다.
            pre, _ = heapq.heappop(hq)
        # 한 사이클을 돌리지 못할때    
        else:
            # 한사이클을 돌리지 못하기 때문에 k와 남은 음식의 개수를 나눈 나머지가 해당 인덱스가 된다.
            idx = k % length
            # 현재 리스트가 섭취시간으로 정렬되어 있어서 두번째 값인 순번으로 정렬해준다.
            hq.sort(key = lambda x: x[1])
            # 답을 찾아주고 멈춰준다
            answer = hq[idx][1]
            break
    return answer

예시의 [3 ,1 ,2] 의 경우의 그림


그림 출처 : https://youtu.be/zpz8SMzwiHM

처음 이 문제를 풀때 왼쪽 그래프처럼 진행되게 풀었고, 결국 완전 탐색으로 연산을 하기 때문에 시간에서도 오류가 났다.
변명을 하자면 입출력 예 설명을 보면서 구상을해서 그런가..
그래서 힙으로 풀어야겠다는 생각은 들었지만 막상 접근하기 어려웠다.

이 후 좋은 설명을 해주셨던 강의를 보고 풀 수 있었다.(해당 그림 아래 링크)

효율적으로 풀려면 오른쪽 그림처럼 되야하는데 해당 그림처럼 정렬을 진행할때 (섭취시간, 순번)의 튜플 구조로 넣어서 남은 k보다 한 사이클이 클때 다시 순번을 기준으로해서 정렬해서 정답 인덱스를 찾아준다.


설명하기 너무 어렵지만.. diff가 섭취시간*음식의 개수(해당 그림의 세로*가로)인데 이것이 앞에서 언급했던 한 사이클을 뜻하는데 섭취시간 순으로 정렬되어 있기 때문에 한번에 많은 수를 줄여 줄 수 있었다.

profile
깃허브로 이전했습니다 -> https://chobae.github.io/

0개의 댓글