본문 바로가기
알고리즘&자료구조/ETC

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

by do_ng 2024. 6. 5.

문제 이해

조건

문제에서 주어진 조건을 잘못 이해하고 넘어가는 경우 코드를 다르게 작성할 수 있으니 초기에 조건을 정확하게 이해하자


1. 차량은 In Out을 여러번 할 수 있음
00~23:59 동안의 해당 차량번호가 얼마나 주차장에 머물렀는지 체크
들어갈때마다 기본 주차요금이 계속 더해지는게 아니라 하루동안에 머물렀던 총 시간을 기준으로 계산

 

로직

전체 로직을 세분화시키고 세분화된 로직별로 처리하면서 진행하자
0.초기값 세팅
Map<String(차량번호),Integer(입차시간)> in
Map<String(차량번호),Integer(경과시간)> out
List<Record> record(차량별 요금 기록)

1.IN 차량이 있으면 시간체크 시작 (O)
-> 입차시간 저장, 처음 In인 경우 경과시간 0으로 초기화

2.OUT 차량이 있으면 경과시간 계산 (O)
-> in에 해당 차량의 입차시간을 -1 처리(in~out이 한세트로 되었다는 의미)
요금을 맨 마지막에 계산하는 이유는 해당 차량이 여러번 출차할 수도 있기 때문

3.모든 records를 뒤졌는데 IN하고 OUT하지 않은 차량이 있으면 23:59 출차로 간주 (O)
-> IN 이후에 OUT하지 않는 차량을 체크하는 방법
입차시간이 -1이 아닌 차량이 있으면 OUT하지 않은 차량으로 체크 후 요금 계산해서 record에 저장    

4.record에 있는 차량을 번호가 작은 순서대로 정렬 후 answer에 저장

 

Java 코드

import java.util.*;

public class Main {

	// carNum으로 정렬 후 fee를 출력하기 위한 클래스 선언
    static class Record implements Comparable<Record> {
        String carNum;
        int fee;

        @Override
        public int compareTo(Record r) {
            return this.carNum.compareTo(r.carNum);
        }
    }
    
    static public int[] solution(int[] fees, String[] records) {
        Map<String, Integer> in = new HashMap<String, Integer>();
        Map<String, Integer> out = new HashMap<String, Integer>();
        
        int recordCnt = records.length;
        for (int i = 0; i < recordCnt; i++) {
          if (records[i].substring(11).equals("IN")) {
            // 입차시간 -> 분으로 변경
            int startTime = Integer.parseInt(records[i].substring(0, 2)) * 60 + Integer.parseInt(records[i].substring(3, 5));
            String carNum = records[i].substring(6, 10);
            in.put(carNum, startTime);        
            // 처음 입차인 경우 경과시간 0으로 세팅(두번째 입차부터 계속 더해져야 됨)
            if(out.get(carNum) == null) {
            	out.put(carNum, 0);	
            }
          } else if (records[i].substring(11).equals("OUT")) {
            String carNum = records[i].substring(6, 10); 
            int endTime = Integer.parseInt(records[i].substring(0, 2)) * 60 + Integer.parseInt(records[i].substring(3, 5));
            int totalTime = endTime - in.get(carNum);
            if(out.get(carNum) != null) {
            	totalTime += out.get(carNum); 
            }    
            in.put(carNum, -1);
            out.put(carNum, totalTime);            
          }
        }

        // 차량별 최종 요금 계산
        List<Record> record = new ArrayList<Record>();
        for(Map.Entry<String, Integer> map : out.entrySet()){
            String carNum = map.getKey();
            int totalTime = map.getValue();
            // In 이후 Out이 없는 차량은 추가적인 시간 계산
            if(in.get(carNum) != -1){
            	totalTime += ((23 * 60 + 59) - in.get(carNum));
            }            
            // 차량별 총 요금 계산
            int totalFee = fees[1];
            if (totalTime > fees[0]) { // 기본시간을 넘는 경우 추가요금 계산
            	// int와 int형의 나눗셈을 할 때 소수점이 나오면 정수형으로 리턴하기 때문에 소수부분이 잘라진다. 그러므로 한쪽을 double or float 같은 소수 타입의 숫자를 사용해야 한다.
            	totalFee = fees[1] + ((int) Math.ceil((double)(totalTime - fees[0]) / fees[2])) * fees[3];
            }                            
            Record r = new Record();
            r.carNum = carNum;
            r.fee = totalFee;
            record.add(r);
        }
            
        Collections.sort(record);
        int[] answer = new int[record.size()];
        for(int i=0;i<record.size();i++){
            answer[i] = record.get(i).fee;
        }
        
        return answer;
      }
    
	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[] answer = solution(fees, records);        
        for(int i=0;i<answer.length;i++){
            System.out.print(answer[i] + " ");
        }
	}
}