📖Problems
코딩테스트 연습 > 고득점 kit > 이분탐색 > 입국심사 LEVEL 3문제입니다.
n
명이 입국심사를 위해 줄을 서서 기다리고 있습니다. 각 입국심사대에 있는 심사관마다 심사하는데 걸리는 시간은 다릅니다.
처음에 모든 심사대는 비어있습니다. 한 심사대에서는 동시에 한 명만 심사를 할 수 있습니다. 가장 앞에 서 있는 사람은 비어 있는 심사대로 가서 심사를 받을 수 있습니다. 하지만 더 빨리 끝나는 심사대가 있으면 기다렸다가 그곳으로 가서 심사를 받을 수도 있습니다.
모든 사람이 심사를 받는데 걸리는 시간을 최소로 하고 싶습니다.
입국심사를 기다리는 사람 수 n
, 각 심사관이 한 명을 심사하는데 걸리는 시간이 담긴 배열 times가 매개변수로 주어질 때, 모든 사람이 심사를 받는데 걸리는 시간의 최솟값을 return 하도록 solution 함수를 작성해주세요.
제한사항
- 입국심사를 기다리는 사람은 1명 이상 1,000,000,000명 이하입니다.
- 각 심사관이 한 명을 심사하는데 걸리는 시간은 1분 이상 1,000,000,000분 이하입니다.
- 심사관은 1명 이상 100,000명 이하입니다.
입출력 예
n | times | return |
---|---|---|
6 | [7, 10] | 28 |
입출력 예 설명
가장 첫 두 사람은 바로 심사를 받으러 갑니다.
7분이 되었을 때, 첫 번째 심사대가 비고 3번째 사람이 심사를 받습니다.
10분이 되었을 때, 두 번째 심사대가 비고 4번째 사람이 심사를 받습니다.
14분이 되었을 때, 첫 번째 심사대가 비고 5번째 사람이 심사를 받습니다.
20분이 되었을 때, 두 번째 심사대가 비지만 6번째 사람이 그곳에서 심사를 받지 않고 1분을 더 기다린 후에 첫 번째 심사대에서 심사를 받으면 28분에 모든 사람의 심사가 끝납니다.
🔍Conception
n명이 입국심사를 받아야 함. 심사를 하는데 걸리는 시간을 나타낸 배열 times를 보고 최소가 되도록 해야 한다.
⇒ 이 문제는 이진탐색 문제로, 먼저 이진탐색 알고리즘에 대해 다시 짚고 넘어갈 필요가 있다.
이분탐색(Binary Search) 알고리즘의 기본 구조
chatGPT
- Set left and right pointers to the first and last indices of the array.
- While the left pointer is less than or equal to the right pointer.
- Calculate the middle index by adding the left and right pointers and dividing by 2.
- If the middle element is equal to the target, return its index.
- If the middle elements is less than the target, set the left pointer to the middle index plus one.
- If the middle elements is greater than the target, set the right pointer to the middle index minus one.
- If the target is not found, return -1.
- 배열의 첫 번째 및 마지막 인덱스에 대한 왼쪽 및 오른쪽 포인터를 설정합니다.
- 왼쪽 포인터가 오른쪽 포인터보다 작거나 같은 경우.
- 왼쪽(
left
)과 오른쪽(right
) 포인터를 추가하고 2로 나누어 중간 지수를 계산합니다. - 중간 요소(
mid
)가 대상(target
)과 같으면 인덱스를 반환합니다. - 중간 요소가 목표값보다 작으면 왼쪽 포인터를 가운데 인덱스에 1을 더한 값으로 설정합니다.
- 중간 요소가 목표값보다 크면 오른쪽 포인터를 가운데 인덱스에서 1을 뺀 값으로 설정합니다.
- 왼쪽(
- 대상을 찾을 수 없으면 -1을 반환합니다.
🔍Institution
이진탐색에서 정해야 할 것은 범위는 어떻게 설정할지, 무엇을 탐색할지, 어떤 기준으로 탐색할지이다.
- 범위 : 심사를 하는데 총 걸리는 시간을 탐색해야 한다. 따라서 최소가 되는 시간부터 가장 오래걸리는(최대가 되는)심사시간으로 설정한다.
- 무엇을 탐색하는가? → 최종 return해야 하는 것이 몇 분이 걸렸는지 최소 시간을 return한다. 따라서, 탐색해야 하는 대상은 걸리는 ‘시간’이다.
mid
: 모든 심사관들에게 주어진 시간이다.- 기준 :
mid
동안 심사를 완료한 사람의 수(completed
)가- 심사 받아야할 사람의 수(n)보다 많거나 같을 경우에는 시간이 충분했던 것이므로 주어진 시간을 줄이고 ( right = mid - 1 -> right 를 줄이면 left와 right의 중간 값인 mid 도 줄어드니까 주어진 시간이 줄어든다.)
- 심사 받아야할 사람의 수(n)보다 적은 경우에는 시간이 부족했던 것이므로 주어진 시간을 늘린다. (left = mid + 1)
이때, 비교해야 하는 값, 즉 몇 명을 탐색했는지 어떻게 아느냐도 관건이다.
mid
= 모든 심사관들에게 주어진 시간이므로,mid // 심사받는데 걸리는 시간
⇒ 검사받은 사람의 수가 된다.
🔍Approach
🚩My submission
left
는times
에서 가장 작은 시간을 넣어준다.right
는 가장 긴 심사시간이 걸리는 경우, 즉times
에서 가장 큰 시간 *n
(인원 수)의 값을 넣어준다.mid
를 설정한다.mid
는left+right // 2
이다.- for문을 이용하여
mid
분동안 입국심사한 사람의 수를 구하여completed
에 저장한다.- 이때,
completed
가n
과 같으면 더 구할 필요가 없으므로break
를 걸어 종료한다.
- 이때,
- 만약 심사한 사람의 수가
n
보다 작을 경우,left
의 값을 변경해준다.mid
를 기준으로 오른쪽으로 가야 하므로mid + 1
- 만약 4번이 아니라면(=심사한 사람의 수가
n
보다 크거나 같을 경우),right
의 값을 변경해준다.mid
를 기준으로 왼쪽으로 가야하므로mid - 1
- 또한, 같은 경우도 포함되어 있으므로,
answer
에도mid
값을 집어넣어준다.
- 또한, 같은 경우도 포함되어 있으므로,
- 위 ~ 과정을
left<=right
까지 반복한다. answer
를 return한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def solution(n, times):
answer = 0
left = min(times)
right = max(times) * n
while left <= right:
mid = (left + right) // 2
completed = 0
for i in range(len(times)):
completed += (mid // times[i])
if completed == n:
break
if completed < n:
left = mid + 1
else: # complete >= n
answer = mid
right = mid - 1
return answer
- 계속 에러가 났었는데 그 이유는 answer = mid와 return answer를 하지 않아서였다.
- complete ≥ n은 즉 complete == n인 것도 포함하기 때문에 값을 answer에 넣어주어야 한다.
💡TIL
- 어떤 것을 target값으로 설정해야 하는지 몰라서 헤맸던 문제였다. 앞으로 target값을 모르겠을 때는 return을 무엇을 해야 하는지 보면 된다는 것을 명심하자!
- 이진 탐색은 ‘이분 탐색의 범위는 무엇으로 할지’와 ‘이분 탐색의 기준을 무엇으로 할지’를 잡아야 한다.