[프로그래머스] 주차요금 계산 (2022 KAKAO BLIND RECRUITMENT)
알고리즘/프로그래머스

[프로그래머스] 주차요금 계산 (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 해준다.