개발 As 공부/Algorithm

[프로그래머스] 주차 요금 계산 - JAVA

민킹 2022. 3. 24. 18:29

문제 보기

문제 개요
input 형식
output 내는 방법

 

문제 분석

[요약]

주차장을 이용한 차량별 요금을 계산 하여 차량 번호 오름차순으로 출력하기. 테스트 케이스별로 기본 시간/요금, 단위 시간/요금이 다름.

 

[푸는 과정]

차량번호를 기준으로 이용시간 체크를 해야겠다. 총 이용시간을 계산 하려면 여러번의 차량번호 검색이 필요하기 때문에 시간초과 방지를 위해 Map을 써야겠다.

주차장 이용 중인 차량 용 Map(=carParkRecords), 각 차량 별 총 이용 시간용 Map(=useTimeRecords) 이렇게 두 가지 맵을 사용할 것이다.

해당 문제에서 각 차량 별 출입 시간을 오름차순으로 제공한다. 그렇기에 carParkRecords에 해당 차량이 있으면, 해당 입력이 해당 차량의 출차 시간을 나타내므로 시간 차이를 계산하여 useTimeRecords를 업데이트 한다. 만약 carParkRecords에 해당 차량이 없다면, 해당 입력은 해당 차량의 입차 시간을 나타내는 것이므로 그냥 carParkRecords에 넣어 준다. 

각 input마다 해당 작업이 끝나면 입차만 하고 아직 출차 하지 않은 차량만 carParkRecords에 남아있을 것이다. 문제에서 해당 차량은 모두 23:59분에 나가는 것으로 간주한다 하였으므로 출차 시간을 23:59분으로 하여 이용시간을 계산 해 준다.

 

코드 보기

import java.text.*;
import java.util.*;

public class Main {
	// 주차장에 들어온 차량 체크용 map
    public Map<Integer, Long> carParkRecords = new HashMap<>();
    // 차량별 누적 사용시간
    public Map<Integer, Long> useTimeRecords = new TreeMap<>();
    public SimpleDateFormat formatter = new SimpleDateFormat("HH:mm", Locale.KOREA);

    public int[] solution(int[] fees, String[] records) throws ParseException {
        int[] answer = {};

        for(int i=0; i<records.length; i++){
            // 1) OUT 기록이 있는 차량의 총 이용시간 계산(in mapForFee)
            parseRecords(records[i]);
        }

        // 2) 출차 기록이 없는 차량의 경우를 계산
        Iterator<Integer> keys = carParkRecords.keySet().iterator();
        while(keys.hasNext()){
            int carNum = keys.next();

            long timeIN = carParkRecords.get(carNum);
            long timeOUT = formatter.parse("23:59").getTime();
            long difference = (timeOUT - timeIN) / 60000;

            calculateTotalMinutes(carNum, difference);
        }

        // 3) 각 차량별 정산
        answer = getTotalFee(fees);
        return answer;
    }

    public void calculateTotalMinutes(int carNum, long difference){
        if(useTimeRecords.containsKey(carNum)){
            useTimeRecords.put(carNum, useTimeRecords.get(carNum) + difference);
        } else{
            useTimeRecords.put(carNum, difference);
        }
    }

    // OUT 기록이 있는 차량의 총 이용시간 계산(in mapForFee)
    public void parseRecords(String record) throws ParseException {
        String[] recordParsed = record.split(" ");
        long time = formatter.parse(recordParsed[0]).getTime();
        int carNum = Integer.parseInt(recordParsed[1]);

        if(!carParkRecords.containsKey(carNum)){
            carParkRecords.put(carNum, time);
        } else{
            long timeIN = carParkRecords.get(carNum);
            long difference = (time - timeIN) / 60000; 
            // 60000 --> (밀리세컨 1000 * 분 60)
            
            calculateTotalMinutes(carNum, difference);
            carParkRecords.remove(carNum);
        }
    }

    // 각 차량별 정산
    public int[] getTotalFee(int[] fees) {
        int[] answer = new int[useTimeRecords.size()];
		
        // 코드 가독성을 위해 변수로 지정
        int basicTime = fees[0];    int basicFee = fees[1];
        double perMin = fees[2];    int perFee = fees[3];

        Object[] mapkey = useTimeRecords.keySet().toArray();
        Arrays.sort(mapkey);

        Iterator<Integer> keys = useTimeRecords.keySet().iterator();
        int index = 0;
        while(keys.hasNext()){
            int carNum = keys.next();
            long totalTime = useTimeRecords.get(carNum);

            if(totalTime < basicTime) {
                answer[index] = basicFee;
            } else{
                answer[index] 
                = (int) (Math.ceil((totalTime - basicTime)/(perMin*1.0))*perFee) + basicFee;
            }
            index++;
        }
        return answer;
    }
}

 

 

개인적으로 다시 보게 된 Point

  1. 시간차이 계산
  2. 숫자의 rounding
  3. ConcurrentModificationException ▶ 처음 코드 제출 시 반 이상의 테스트 케이스가 'RunTimeError'로 떴던 원인
  4. TreeMap