[프로그래머스] level2 주차 요금 계산 - 구현
1. 문제
문제 설명
문제 설명
주차장의 요금표와 차량이 들어오고(입차) 나간(출차) 기록이 주어졌을 때, 차량별로 주차 요금을 계산하려고 합니다. 아래는 하나의 예시를 나타냅니다.
- 요금표
- 입/출차 기록
시각(시:분)차량 번호내역
- 자동차별 주차 요금
차량 번호누적 주차 시간(분)주차 요금(원)
- 어떤 차량이 입차된 후에 출차된 내역이 없다면, 23:59에 출차된 것으로 간주합니다.
- 0000번 차량은 18:59에 입차된 이후, 출차된 내역이 없습니다. 따라서, 23:59에 출차된 것으로 간주합니다.
- 00:00부터 23:59까지의 입/출차 내역을 바탕으로 차량별 누적 주차 시간을 계산하여 요금을 일괄로 정산합니다.
- 누적 주차 시간이 기본 시간이하라면, 기본 요금을 청구합니다.
- 누적 주차 시간이 기본 시간을 초과하면, 기본 요금에 더해서, 초과한 시간에 대해서 단위 시간 마다 단위 요금을 청구합니다.
- 초과한 시간이 단위 시간으로 나누어 떨어지지 않으면, 올림합니다.
- ⌈a⌉ : a보다 작지 않은 최소의 정수를 의미합니다. 즉, 올림을 의미합니다.
주차 요금을 나타내는 정수 배열 fees, 자동차의 입/출차 내역을 나타내는 문자열 배열 records가 매개변수로 주어집니다. 차량 번호가 작은 자동차부터 청구할 주차 요금을 차례대로 정수 배열에 담아서 return 하도록 solution 함수를 완성해주세요.
2. 구현
입출차만 관리하면서 비용을 계산하면 될 것이라고 생각하고 구현
입차
`hastMap`이용해서 <차 번호 : 입차시간> 을 저장하기로 함.
이때 시간 계산의 편의를 위해 입차시간은 분 단위로 int형태로 계산하기로 함
# "01:30" -> 1*60 + 30 => 90
출차
1. 주차 요금 구하기 : `hastMap`에 저장된 입차시간과 출차시간을 가지고 총 비용을 구함
2. 결과 저장 : 바로 `outCars` 리스트에 저장.
3. `hashMap`에서 삭제 : 그리고 출차된 차량임을 알기위해 `hashMap`에서 삭제.
하지만 풀다가 놓친 점
1. 같은 차가 하루에 2번 이상올 수 있음
2. 나갈 때마다 계산하는 것이 아니라 하루 누적금액을 계산하는 거였음
3. 또한 출력결과가 차 번호 순대로 비용을 출력해야 하니, 결과를 저장하는 `outCars` 는 트리맵으로 구성
다시 구현
입차
바뀌지 않음
출차
1. 결과 저장 List -> TreeMap으로 : ,이때 비용을 계산하고 결과 리스트에 저장하는 것이 아니라, 누적된 주차 시간을 별도의 `outCars` 트리맵에 <차 번호 : 누적된 주차 시간>을 저장하기로 함. 마찬가지로 출차된 차량임을 알기위해 `hashMap`에서 삭제.
3. 어려웠던 점
1. 결과 소수점에서 올림하기
-> `Math.ceil` 함수를 이용하면 올림할 수 있음
# 1.1 -> 2
2. 정수의 연산에 Math.ceil 해봤자 이미 소수점이 날아갔음
계속 올림이 안되길래 뭐가 문제지 보다가, int 형/ int 형 때문에 이미 소수점 내림이 되고 있었음
3. stream
리스트를 배열로 전환할 때 코드가 너무 더러워서 stream 찾아봄
전
int [] costs = new int[outCars.size()];
int idx = 0;
for(String c : outCars.keySet()){
int t = outCars.get(c);
int operTime = outCars.get(c);
if(operTime <= baseTime){
costs[idx++] = baseCost;
}
else{
costs[idx++] = baseCost + (int)(Math.ceil((operTime - baseTime)*1.0 / perTime)) * perCost;
}
후
return outCars.values()
.stream()
.mapToInt(time -> calculateFee(time, baseTime, baseCost, perTime, perCost)).toArray();
4. 전체 코드
import java.util.*;
class Solution {
public int[] solution(int[] fees, String[] records) {
int[] answer = {};
// 1. 변수 선언
int baseTime = fees[0];
int baseCost = fees[1];
int perTime = fees[2];
int perCost = fees[3];
HashMap<String, Integer> inCars = new HashMap<String, Integer>();
TreeMap<String, Integer> outCars = new TreeMap<String, Integer>();
// 2. 레코드 마다 관리
for(String record : records){
String [] op = record.split(" ");
int time = timeToInt(op[0]);
String carNum = op[1];
if(op[2].equals("IN")){
// 입차 - 해쉬셋에 (차 번호 : 입차시간) 저장, 입차시간은 분단위
inCars.put(carNum, time);
}
else if(op[2].equals("OUT")){
// 출차 - 입차 시간 계산, 차 삭제, 레코드 저장
int inTime = inCars.get(carNum);
outCars.put(carNum, outCars.getOrDefault(carNum, 0) + (time - inCars.remove(carNum)));
}
}
// 출차되지 않은 차 출차
int endOfDay = 60*23 + 59;
for(String car : inCars.keySet()){
int inTime = inCars.get(car);
outCars.put(car, outCars.getOrDefault(car, 0) + (endOfDay - inTime));
}
return outCars.values()
.stream()
.mapToInt(time -> calculateFee(time, baseTime, baseCost, perTime, perCost)).toArray();
}
private int calculateFee(int time, int baseTime, int baseCost, int perTime, int perCost) {
if (time <= baseTime) return baseCost;
return baseCost + (int) Math.ceil((time - baseTime) / (double) perTime) * perCost;
}
public static int timeToInt(String time){
String [] st = time.split(":");
int h = Integer.parseInt(st[0]);
int m = Integer.parseInt(st[1]);
return h*60 + m;
}
}