2018년 카카오 blind 코딩 테스트 - 무지의 먹방 라이브 python
출처 : https://programmers.co.kr/learn/courses/30/lessons/42891
문제 풀이
단순 무식한 방법으로 List를 k만큼 돌면서 각 원소 값을 -1로 줄이고, 0인 경우는 인덱스를 뛰어넘어가면서 검사하면서 최종 인덱스를 반환하는 방식으로 구현하면 효율성 검사에서 시간 초과하게 됩니다.
food_times [10, 4, 6] k=17인 경우
빠르게 검색하는 방법은 food_times에서 오름 차순으로 정렬하여 제일 적은 시간이 먼저가게 배치하는 것입니다.
정렬을 하면 다음과 같이 되겠죠 -> food_times [4(#2), 6(#3), 10(#1)]
k와 비교를 할 것인데 만약 제일 적은 시간(4)를 다 먹기 위해서 k가 몇 번을 돌아야 할까요?
전체 배열을 3바퀴를 돌아 4번을 먹어치우면 0 이됩니다. 그러면 k 는 4*3 = 12 만큼 움직였습니다.
일반화시키면 전체 원소 길이 length = len(food_times)와 제일 적은 시간 min_foods 라고 명명하면 k = length * min_foods 이겠죠? - min_foods를 뽑는 방식을 생각해보면 우선순위 큐(Priority Queue)를 사용하여 값을 오름차순 정렬로 제일 작은 값을 빼내는 get()을 쓰면 되겠다가 생각하면 정말 좋겠죠 :D 이렇게 되면, 제일 적은 시간의 음식은 빠져나가게 되고 length는 하나 줄게 됩니다. length -= 1
자 그렇게 되면 남은 음식은 [6(#3), 10(#1)] 값을 업데이트 해보면 각기 4번 돌았으니깐 [2(#3), 6(#1)] 그리고 k 값을 업데이트 해보죠. 위에서 12번 썼으니 k=(17-12)=5이 됩니다.
위와 같이 또 적은 음식의 남은 시간 2초를 없애려면 2번 돌아야합니다.
2*2=4 입니다.
자 지금의 과정을 풀어써봅시다. 현재 #3의 6에서 이전의 단계의 음식 #2의 4를 뺐습니다. 6-4 = 2 그리고 지금 현재의 배열의 길이인 length 2죠. 그래서 소모되는 k값은 2*2=4가 되었습니다.
즉 우리는 이전(빼버린) 음식의 시간 값을 기억해야 하고, 지금의 값과 비교할 것이며, 또한 전체 길이 food_times의 length 도 과일을 뺄 때마다 -1을 해줘야 한다는 풀이 과정이 생깁니다.
자 그래서 업데이트하면 [2(#1)] k =(5-4)1가 됩니다.
k가 남은 현재 시간보다 적기 때문에 위의 과정을 멈추고 풀어씁니다.
[2(#1)] -> [1(#1)] [1(#1)]
여기서 k=1일 경우에 우리의 문제는 다음에 먹을 과일은 무엇인지 물어보기 때문에 원하는 위치의 값은 k+1이죠
그래서 2번째인 #1을 정답으로 반환하면 됩니다.
여기서 푸는 방식은 값을 기준으로 오름차순으로 정렬되는 우선순위 큐(Priority Queue)를 사용합니다.
우선순위 큐는 일반적인 큐의 순서대로 원소를 제거하는 선입선출(FIFO) 방식이 아니라, 순서에 상관없이 추가가 되어도 값을 뽑을 때는 가장 작은값(오름차순)을 제거하는 특성을 지닌 자료 구조 입니다.
from queue import PriorityQueue를 사용하면 됩니다. PriorityQueue에 데이터를 넣는 것은 put(), 뽑는 것은 get()을 사용할 것이고, 데이터를 넣을 때는 Tuple 형식으로 (정렬되는 기준 key 값, value값) 넣어주면 됩니다.
[1] 만약 더 섭취해야 할 음식이 없다면 -1을 반환합니다. 즉 k라는 시간이 food_times 전체 합보다 크거나 같으면 더 이상 먹을 음식이 없습니다.
[2] 다음으로는 우선순위 큐에다가 (food_times의 음식 먹는데 필요한 시간, 음식 index)를 추가합니다.
[3] 위의 과정처럼 현재 상황에서 제일 적은 시간을 가진 음식을 뺄 수 있는지 while() 이용해서 조건을 검사합니다.
- (누적되어 빼버린 k값) + (빼버릴 음식의 시간 - 이전 음식의 시간) / (현재 음식의 개수) < 현재 k값
- 현재 제일 적은 시간을 가진 음식(now)을 뺄 수 있다면 queue.get()으로 빼버리고,
- k값은 업데이트가 now - previous(이전에 빼버린 음식) * (현재 음식의 개수) 빼버리겠죠?
- 음식이 하나 빠져버리니 현재 음식의 개수(length)도 하나로 줄 것이고, previous 도 업데이트 됩니다.
[4] k값 기준으로 k 값이 작아서 더 이상 현재 제일 적은 시간 음식을 빼버릴 수 없다면 while문은 멈춥니다.
[5] 자 그러면 남은 음식들은 queue값에 있을 테고, 지금 현재 값 계산이 오름 차순으로 정렬으로 했으니 다시 원래 형태로 인덱스 기준 정렬 먼저 합니다. sorted(q.queue, key=lambda x:x[1])
[6] 최종적으로 남은 음식과 최종 k를 이용해서 몇 번째 음식이니 확인하려면 %(mod)를 이용하면 쉽습니다.
최종적으로 남은 음식이 2개이고, k=5번이라고 가정하고 위치를 계산하라면 5%2 = 1
List에서 인덱스 계산은 0부터 시작이니 k+1은 고려 안해도 됩니다.
'Algorithm' 카테고리의 다른 글
codility - binary gap python (0) | 2019.09.22 |
---|---|
2018년 카카오 blind 코딩 테스트 - 길 찾기 게임 python (0) | 2019.09.21 |
2018년 카카오 blind 코딩 테스트 - 후보키 python (0) | 2019.09.21 |
2018년 카카오 blind 코딩 테스트 - 실패율 python (0) | 2019.09.21 |
2018년 카카오 blind 코딩 테스트 - 오픈채팅방 python (0) | 2019.09.21 |