[프로그래머스] 주차요금 계산 (2022 KAKAO BLIND RECRUITMENT)
주차요금 계산
https://programmers.co.kr/learn/courses/30/lessons/92341?language=javascript
코딩테스트 연습 - 주차 요금 계산
[180, 5000, 10, 600] ["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"] [14600, 34400, 5000]
programmers.co.kr
풀이
function solution(fees, records) {
const getTimeByMinute = time => {
if(!time) return 0;
const times = time.split(':');
const [hour, minute] = times;
return (hour * 60) + parseInt(minute);
}
const LAST_OUT_TIME = getTimeByMinute("23:59");
const totalTimeByCar = records.reduce((totalTimeByCar, record) => {
const [recordTime, carNumber, status] = record.split(" ");
const minutes = getTimeByMinute(recordTime);
const totalTime = totalTimeByCar[carNumber] || 0;
const time = status === 'IN' ? LAST_OUT_TIME - minutes : minutes - LAST_OUT_TIME;
return {...totalTimeByCar, [carNumber]: totalTime + time}
}, {});
const getTotalFee = (time, fees) => {
const [basicTime, basicFee, additionalTime, additionalFee] = fees;
if(time <= basicTime) return basicFee;
return basicFee + Math.ceil((time - basicTime) / additionalTime) * additionalFee;
}
return Object.keys(totalTimeByCar).sort().map(carNumber => getTotalFee(totalTimeByCar[carNumber], fees));
}
✔️ 주요 전제 조건
- 입차 후 출차 기록이 없을 시에는
23:59
에 출차한 것으로 간주한다. - 누적 주차시간 ≤ 기본시간 까지는 기본요금(
basicFee
)을 부과한다. - 만약
추가 시간 / 단위 시간
이 나누어떨어지지 않으면 올림 한다. records
는 시각의 오름차순으로 정렬되어있다.- 차량번호가 작은 순으로 청구할 주차요금을 배열로
return
const getTimeByMinute = time => {
if(!time) return 0;
const times = time.split(':');
const [hour, minute] = times;
return (hour * 60) + parseInt(minute);
}
const LAST_OUT_TIME = getTimeByMinute("23:59");
모든 시간은 분단위로 바꿔서 계산해야 하기 때문에 기존의 HH:MM
형식의 시간을 분단위로 바꿔주는 메서드를 생성했다.
입차 후 출차 기록이 없을 시에는 가장 마지막 시간인 23:59에 출차한 걸로 간주하기 때문에 미리 23:59를 분단위로 환산한 값을 LAST_OUT_TIME
에 넣어놓았다.
records
를 순회하면서 { [차량번호] : 총 주차시간 }
형식으로 값을 객체에 담아줄 것이다.
const totalTimeByCar = records.reduce((totalTimeByCar, record) => {
const [recordTime, carNumber, status] = record.split(" ");
const minutes = getTimeByMinute(recordTime);
const totalTime = totalTimeByCar[carNumber] || 0;
const time = status === 'IN' ? LAST_OUT_TIME - minutes : minutes - LAST_OUT_TIME;
return {...totalTimeByCar, [carNumber]: totalTime + time}
}, {});
- records는 하루 동안의 입/출차된 기록만 담고 있으며, 입차 된 차량이 다음날 출차되는 경우는 입력으로 주어지지 않습니다.
- 같은 시각에, 같은 차량번호의 내역이 2번 이상 나타내지 않습니다.
- 마지막 시각(23:59)에 입차 되는 경우는 입력으로 주어지지 않습니다.
- 아래의 예를 포함하여, 잘못된 입력은 주어지지 않습니다.
- 주차장에 없는 차량이 출차되는 경우
- 주차장에 이미 있는 차량(차량번호가 같은 차량)이 다시 입차되는 경우
위의 제한사항을 살펴보면 무조건 하나의 차량에 대한 기록은 입차 → 출차의 순으로 이루어진다. ( 입차를 끝으로 기록이 없을 수는 있다 )
예외 상황이 없기 때문에, 총 주차시간을 구하기 위해서는 입차 시간을 빼주고, 출차시간을 더해주면 된다.
❗️ 단, 한 가지 고려해야 하는 상황은 입차를 끝으로 기록이 끝난다면, 출차시간으로 LAST_OUT_TIME
을 더해줘야 하는데 이 경우를 어떻게 파악하는지 였다.
const time = status === 'IN' ? LAST_OUT_TIME - minutes : minutes - LAST_OUT_TIME;
입차기록 + LAST_OUT_TIME
출차기록 - LAST_OUT_TIME
그래서 생각한 방법이 모든 입・출차 기록에 LAST_OUT_TIME
을 더하고 빼주는 것이었다.
입차일때는 값에 LAST_OUT_TIME
을 더해주고, 출차일때는 입차 때 더했던 LAST_OUT_TIME
값을 상쇄시키기 위해 LAST_OUT_TIME
을 빼준다. 이렇게 하면, 입차 후 출차 기록이 없을 때는 자동으로 LAST_OUT_TIME
값이 더해지게 된다.
const getTotalFee = (time, fees) => {
const [basicTime, basicFee, additionalTime, additionalFee] = fees;
if(time <= basicTime) return basicFee;
return basicFee + Math.ceil((time - basicTime) / additionalTime) * additionalFee;
}
이제 총 주차 요금을 구한다.
주차시간이 기본 시간을 초과하지 않는다면 기본요금, 초과하면 단위 시간으로 추가 요금을 계산해서 리턴한다.
return Object.keys(totalTimeByCar).sort().map(carNumber => getTotalFee(totalTimeByCar[carNumber], fees));
차량번호가 작은 순으로 결과를 return
해줘야 하기 때문에 차량번호로 정렬한 후 총 주차요금을 담아서 return
해준다.