프로그래머스

[코딩테스트 연습] 주차 요금 계산 - Lv.2

yujin0517 2024. 2. 1. 17:20

주차 요금 계산 - Lv.2

 

<문제>

https://school.programmers.co.kr/learn/courses/30/lessons/92341

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

<문제 풀이>

HashMap, TreeMap(정렬을 위해)를 사용하여 각 차량의 입차 시간과 총 주차 시간을 저장했다.

이 문제는 여러 가지 조건들을 통해 구현 능력을 확인하고, 자료구조를 적절히 활용하는 것에 초점은 둔 것 같다. 

차량의 입차 시간을 저장하는 inTime Map과 차량의 총 주차 시간을 저장하는 parking Map을 선언했다. 

차량 번호가 아닌 입/출차를 의미하는 "IN"/"OUT"을 중심으로 코드를 작성했다.

 

차량이 주차장에 들어오면(IN) inTime에 차량 번호와 입차 시간을 저장하고, 차량이 주차장을 나가면(OUT) 출차 시간에서 입차 시간을 뺀 만큼과 차량 번호는 parking에 저장한다. 

parking에 저장된 총 주차 시간을 가지고 초과 요금을 계산해 최종적으로 반환되는 배열에 저장한다. 

 

이 문제를 풀 때, 계속 런타임 에러가 걸렸던 부분이 있다.

"inTime.remove(entrySet.getKey());" 부분이다. 이 코드가 작성되어 있는 영역은 컬렉션이 순회하고 있는 영역이다. 

즉, entrySet.getKey() 값이 사용되고 있는 상황에서 값을 삭제하면 동시성의 오류가 발생한다. 

컬렉션 순회 중에는 iterator.remove()를 통해서만 값을 삭제할 수 있다. 

해당 코드를 주석처리 해주면 런타임 에러가 발생하지 않는다. 

 

<코드>

import java.util.Map;
import java.util.HashMap;
import java.util.TreeMap;
import java.util.Map.Entry;

public class parkingFee {

	public static void main(String[] args) {
		int[] fees = {180, 5000, 10, 600};
		String[] records = {"05:34 5961 IN", "06:00 0000 IN", "06:34 0000 OUT", "07:59 5961 OUT", "07:59 0148 IN", "18:59 0000 IN", "19:09 0148 OUT", "22:59 5961 IN", "23:00 5961 OUT"};
		
		int[] result = solution(fees, records);
		for(int re : result) {
			System.out.print(re + " ");
		}
	}
	
	public static int[] solution(int[] fees, String[] records) {
        //00:00 ~ 23:59
        //입차 기록은 있지만 출차 기록이 없다면 23:59분에 출차한 것으로 간주함
        //((주차 총 시간 - fees[0]) / fees[2]) * fees[3] + fees[1]
        //HashMap<차량 번호, 입차 시간> inTime; String, String
        //HashMap<차량 번호, 주차 시간> parking; String, Integer
        
        int[] answer = {};
        Map<String, Integer> parking = new TreeMap<>(); //차량의 총 주차 시간
        Map<String, String> inTime = new HashMap<>(); //차량의 입차 시간
        
        for(String record : records) {
            String[] info = record.split(" ");
            
            if(info[2].equals("IN")) { //입차
                inTime.put(info[1], info[0]);
            } else if(info[2].equals("OUT")){ //출차
                int inTimeMin = calTime(inTime.get(info[1]));
                int outTimeMin = calTime(info[0]);
                int allTime = outTimeMin - inTimeMin;
                
                if(parking.containsKey(info[1])) {
                    parking.put(info[1], parking.get(info[1]) + allTime);
                } else {
                    parking.put(info[1], allTime);
                }
                
                inTime.remove(info[1]);
            }
        }
        
        if(!inTime.isEmpty()) {
            for(Entry<String, String> entrySet : inTime.entrySet()) {
                int inTimeMin = calTime(entrySet.getValue()); 
                int outTimeMin = calTime("23:59");
                int allTime = outTimeMin - inTimeMin;
                
                if(parking.containsKey(entrySet.getKey())) {
                    parking.put(entrySet.getKey(), parking.get(entrySet.getKey()) + allTime);
                } else {
                    parking.put(entrySet.getKey(), allTime);
                }
                
                //inTime.remove(entrySet.getKey()); //-> 런타임오류 발생 이유
                //keySet()을 이미 사용하고 있는 상황에서 키를 삭제해서 동시성의 오류가 발생한 것
            }
        }
        
        answer = new int[parking.size()];
        int idx = 0;
        
        for(Entry<String, Integer> entrySet : parking.entrySet()) {
            int time = entrySet.getValue();
            
            if(time <= fees[0]) { //기본 시간만큼 주차한 경우
                answer[idx] = fees[1];
            } else { //초과 시간 계산
            	answer[idx] = fees[1] + (int) Math.ceil((time - fees[0]) / (double)fees[2]) * fees[3];
            }
            idx++;
        }
        
        return answer;
    }
    
    public static int calTime(String time) { //hh:MM -> MM
        String[] timeArr = time.split(":");
        return (Integer.parseInt(timeArr[0]) * 60) + Integer.parseInt(timeArr[1]);
    }
}