Study/Problem Solving

[프로그래머스 / Java] 입국심사 (Lv.3)

Pearlii 2023. 9. 30. 00:36

문제 풀이 날짜: 2023.09.18
포스트 작성일: 2023.09.30

 

* 학습 목적으로 작성하는 글입니다. 풀이가 정석적이지 못할 수도 있습니다.

 

문제 출처

프로그래머스 : 입국심사 (Lv.3)

 

키워드

이분 탐색

 

풀이 접근법

  • 이분탐색은 탐색 범위를 좁혀가면서 최댓값&최솟값 또는 근사치를 찾을 때에 유용하게 사용된다.
  • “모든 사람이 심사를 받는 데 걸리는 시간의 최솟값”의 의미
    • 검사를 완료한 사람이 n명에 다다를 때까지 반복하고 그 lower bound를 구한다.
    • 누적 소요 시간이 k초일 때 이를 각 검색대 별 소요 시간으로 나누어보면 검사를 마친 인원 수가 계산된다.
    • 검사 완료된 인원수가 [n - 1, n - 1, n, n, n, n, n + 1, …] 이라면 n이 처음 출현한 시간을 구해야 함 ⇒ 이것이 최소 시간
    • 굳이 여러 구간을 동시에 탐색하지 않아도 현재까지의 경과 시간을 각 검색대별 시간으로 나눠보면 각 검색대별로 심사를 마친 인원을 모두 구할 수 있다.
    • 시간이 빠른 순서부터 검사를 받아보아야 하므로 입력 배열을 정렬한다.
  •  이분탐색의 start와 end는 무엇으로 정의하는 게 좋은가?
    • 각 검색대 별로 가장 짧은 소요시간부터 (검색대의 최대 소모 시간 × 인원수)까지 탐색한다.
    • 탐색을 멈추는 key 값은 모든 검색대에서 심사를 마친 인원수이다. (key == n)
  • 주어진 입력들의 합을 구하다보면 오버플로우가 날 위험이 있으므로 변수를 long타입으로 선언하여 푼다.

 

코드

import java.util.*;

class Solution {
    public long solution(int n, int[] times) {
        long answer = Long.MAX_VALUE;
        
        Arrays.sort(times);
        
        long start = times[0];
        long end = times[times.length - 1] * (long)n;
        
        while(start <= end) {
            //오버플로우 발생 가능(1)
            long mid = start + ((end - start) / 2);
            
            long sum = 0;
            for(int t : times) {
                long numOfPeople = mid / t; //오버플로우 발생 가능(2)
                sum += numOfPeople;
            }

            if(sum >= n) { //lower bound를 찾으며 범위를 좁힌다
                answer = Math.min(answer, mid);
                end = mid - 1;
            }
            else { //(sum < n)
                start = mid + 1;
            }
        }
        
        return answer;
    }
}

 

 

참고한 링크

https://suhyeokeee.tistory.com/183