본문 바로가기
Problem Solving/프로그래머스

[프로그래머스 | 파이썬 / 자바스크립트] 주차 요금 계산(2022 KAKAO BLIND RECRUITMENT/ level 2)

by 청량리 물냉면 2023. 3. 3.
반응형
문제

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

 

프로그래머스

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

programmers.co.kr

 

 

🐍파이썬

전체 코드

import math
def solution(fees, records):
    answer = []
    temp = {}
    parking = {}
    
    for record in records:
        time, car, inout = record.split()
        if car not in temp:
            temp[car] = time
        else:
            if inout == "OUT":
                parkingTime = (int(time.split(":")[0]) * 60 + int(time.split(":")[1])) - (int(temp[car].split(":")[0]) * 60 + int(temp[car].split(":")[1]))
                if car not in parking:
                    parking[car] = parkingTime
                else:
                    parking[car] += parkingTime
                del(temp[car])
                
    for remain in temp.keys():
        parkingTime = 23 * 60 + 59 - (int(temp[remain].split(":")[0]) * 60 + int(temp[remain].split(":")[1]))
        if remain not in parking:
            parking[remain] = parkingTime
        else:
            parking[remain] += parkingTime
            
    for i in parking.keys():
        totalPay = fees[1] + math.ceil(max(0, (parking[i] - fees[0])) / fees[2]) * fees[3]
        parking[i] = totalPay
        
    for i in sorted(parking.items()):
        answer.append(i[1])
        
    return answer

전체코드(코드 + 문제 풀이 설명 주석)

import math
def solution(fees, records):
    answer = []
    temp = {}
    parking = {}
    
    for record in records:
        time, car, inout = record.split()
        if car not in temp: #temp 딕셔너리에 차 번호로 된 key가 존재하지 않는다면
            temp[car] = time    #새로운 key-value(차 번호:입차시간) 저장
        else:   #temp 딕셔너리에 차 번호로 된 key가 존재한다면(입차내역이 존재한다면)
            if inout == "OUT":  #출차시간 확인
                #주차시간 = 출차시간 - 입차시간 (분단위로 계산하기 위해 '시'에 60을 곱함) 
                parkingTime = (int(time.split(":")[0]) * 60 + int(time.split(":")[1])) - (int(temp[car].split(":")[0]) * 60 + int(temp[car].split(":")[1]))
                if car not in parking: #parking 딕셔너리에 차 번호로 된 key가 존재하지 않는다면
                    parking[car] = parkingTime  #새로운 key-value(차 번호:주차시간) 저장
                else:
                    parking[car] += parkingTime #기존 저장된 주차시간에 새로 구한 주차시간 더함
                del(temp[car])  #주차시간을 모두 구한 차는 temp에서 삭제
                
    for remain in temp.keys():  #IN-OUT 쌍이 맞지 않는 차
        parkingTime = 23 * 60 + 59 - (int(temp[remain].split(":")[0]) * 60 + int(temp[remain].split(":")[1]))   #23:59 - 입차시간
        if remain not in parking:   #parking 딕셔너리에 key가 존재하지 않는다면
            parking[remain] = parkingTime   #새로운 key-value(차 번호:주차시간) 저장
        else:
            parking[remain] += parkingTime  #기존 저장된 주차시간에 새로 구한 주차시간 더함
            
    for i in parking.keys():    #전체 parking 요소들에 대해 요금 계산
        totalPay = fees[1] + math.ceil(max(0, (parking[i] - fees[0])) / fees[2]) * fees[3]  #주차시간이 주차기본제공시간보다 작을 경우 (-)가 나오는 것을 방지하기 위해 max(0, ~) 지정
        parking[i] = totalPay   #parking에 주차시간 대신 주차요금을 저장
        
    for i in sorted(parking.items()):   #key를 기준으로 정렬된 사전을 순회하며 2번째 요소(주차요금)를 정답 배열에 append
        answer.append(i[1])
        
    return answer

💡 key를 기준으로 딕셔너리 정렬하기

  • sorted() 함수 사용
dic = {'0000': 14600, '5961': 5000, '0148': 34400}
newD = sorted(dic.items())
print(newD)
# [('0000', 14600), ('0148', 34400), ('5961', 5000)]
# items() 함수는 key-value 쌍이 튜플 형태로 구성된 리스트를 반환한다.

(참고:https://tinyurl.com/2jr73pop)

 

[Python] 딕셔너리 정렬하기

파이썬 딕셔너리에 입력된 key 값과 value 값들을 정렬해야 할 때가 있습니다.그럴 때 해결할 수 있는 방법을 사용해보려고 합니다. 각각 Key를 이용한 방법과 Value를 이용한 방법이 있습니다.딕셔

kkamikoon.tistory.com

 

 

다른 풀이 방법

from collections import defaultdict
from math import ceil

class Parking:
    def __init__(self, fees):
        self.fees = fees
        self.in_flag = False
        self.in_time = 0
        self.total = 0

    def update(self, t, inout):
        self.in_flag = True if inout=='IN' else False
        if self.in_flag:  self.in_time = str2int(t)	#inout=='IN'
        else:             self.total  += (str2int(t)-self.in_time)

    def calc_fee(self):
        if self.in_flag: self.update('23:59', 'out')
        add_t = self.total - self.fees[0]
        return self.fees[1] + ceil(add_t/self.fees[2]) * self.fees[3] if add_t >= 0 else self.fees[1]

def str2int(string):
    return int(string[:2])*60 + int(string[3:])

def solution(fees, records):
    recordsDict = defaultdict(lambda:Parking(fees))
    for rcd in records:
        t, car, inout = rcd.split()
        recordsDict[car].update(t, inout)
    return [v.calc_fee() for k, v in sorted(recordsDict.items())]

딕셔너리 defaultdict

일반적인 딕셔너리의 경우, 딕셔너리에 존재하지 않는 key에 대해 접근할 경우 keyError가 발생한다. 반면 defaultdic의 경우 key값이 존재하지 않아도 default값을 줄 수 있어 에러가 발생하지 않는다.

(참고: https://tinyurl.com/2l6vytxa)


import math

def solution(fees, records):
    check = {}

    for record in records:
        time, number, status = record.split()
        time = time.split(':')
        time = int(time[0])*60 + int(time[1])
        if number not in check:
            check[number] = (0, time, status)
        if status == 'IN':
            check[number] = (check[number][0], time, status)
        elif status == 'OUT':
            total_time, in_time, _ = check[number]
            total_time += time - in_time
            check[number] = (total_time, time, status)

    result = {}

    for number in check.keys():
        total_time, time, status = check[number]
        if status == 'IN':
            total_time += 1439 - time
        fee = fees[1]
        if total_time <= fees[0]:
            result[number] = fee
        else:
            fee = fee + math.ceil((total_time - fees[0]) / fees[2]) * fees[-1]
            result[number] = fee

    return list(map(lambda x : x[1], sorted(result.items())))

 

 

🐥자바스크립트
function solution(fees, records) {
    var answer = [];
    let temp = {};
    var parking = {};
    let parkingTime = 0;
    
    for(let i of records){
        let [time, car, inout] = i.split(' ');
        if(car in temp == false){
            temp[car] = time;
        } else{
            if(inout === "OUT"){
                parkingTime = (Number(time.split(':')[0]) * 60 + Number(time.split(':')[1])) - (Number(temp[car].split(':')[0]) * 60 + Number(temp[car].split(':')[1]));
                if(car in parking === false){
                    parking[car] = parkingTime;
                } else{
                    parking[car] += parkingTime;
                }
                delete temp[car];
            }
        }
    }

    for(let i in temp){
        if(i in parking === false){
            parking[i] = 23 * 60 + 59 - (Number(temp[i].split(':')[0]) * 60 + Number(temp[i].split(':')[1]));
        } else{
            parking[i] += 23 * 60 + 59 - (Number(temp[i].split(':')[0]) * 60 + Number(temp[i].split(':')[1]));
        }
    }

    for(let i in parking){
        let parkingPay = fees[1] + Math.ceil((Math.max(0, parking[i] - fees[0])) / fees[2]) * fees[3];
        answer.push([i, parkingPay]);
    }
    return answer.sort((a, b) => a[0] - b[0]).map(v => v[1]);
}

전체코드(코드 + 문제 풀이 설명 주석)

function solution(fees, records) {
    var answer = [];
    let temp = {};
    var parking = {};
    let parkingTime = 0;
    
    for(let i of records){
        let [time, car, inout] = i.split(' ');
        if(car in temp == false){	//temp 딕셔너리에 car key가 없을 경우
            temp[car] = time;	//(차번호:입차시간) 저장
        } else{
            if(inout === "OUT"){	//IN-OUT쌍이 지어진 경우
            	//parkingTime = 현재시간 - 입차시간
                parkingTime = (Number(time.split(':')[0]) * 60 + Number(time.split(':')[1])) - (Number(temp[car].split(':')[0]) * 60 + Number(temp[car].split(':')[1]));
                if(car in parking === false){	//parking 딕셔너리에 car key가 없을 경우
                    parking[car] = parkingTime;	//(차번호:주차시간) 저장
                } else{
                    parking[car] += parkingTime;	//기존 car key에 새로 구한 주차시간 더하기
                }
                delete temp[car];	//IN-OUT쌍이 지어졌고 주차시간을 parking 딕셔너리에 저장했으니 temp 딕셔너리 내용 삭제
            }
        }
    }

    for(let i in temp){	//IN-OUT 쌍이 만들어지지 못한 경우
        if(i in parking === false){	//parking 딕셔너리에 temp key가 없을 경우
        	//(23:59 - 현재시간)을 parking 딕셔너리에 저장
            parking[i] = 23 * 60 + 59 - (Number(temp[i].split(':')[0]) * 60 + Number(temp[i].split(':')[1]));
        } else{
            parking[i] += 23 * 60 + 59 - (Number(temp[i].split(':')[0]) * 60 + Number(temp[i].split(':')[1]));
        }
    }

    for(let i in parking){	//parking 딕셔너리를 순회하며 주차비를 계산
        let parkingPay = fees[1] + Math.ceil((Math.max(0, parking[i] - fees[0])) / fees[2]) * fees[3];
        answer.push([i, parkingPay]);
    }
    return answer.sort((a, b) => a[0] - b[0]).map(v => v[1]);
}

 

 

다른 풀이 방법

function solution(fees, records) {
    const parkingTime = {};
    records.forEach(r => {
        let [time, id, type] = r.split(' ');
        let [h, m] = time.split(':');
        time = (h * 1) * 60 + (m * 1);
        if (!parkingTime[id]) parkingTime[id] = 0;
        if (type === 'IN') parkingTime[id] += (1439 - time);
        if (type === 'OUT') parkingTime[id] -= (1439 - time);
    });
    const answer = [];
    for (let [car, time] of Object.entries(parkingTime)) {
        if (time <= fees[0]) time = fees[1];
        else time = Math.ceil((time - fees[0]) / fees[2]) * fees[3] + fees[1]
        answer.push([car, time]);
    }
    return answer.sort((a, b) => a[0] - b[0]).map(v => v[1]);
}
// 차량번호 오름차순으로 청구요금 담아 배열로 리턴

// 청구요금 구하기
// 기본요금 fee[1] + ( 주차시간 - 기본시간fee[0] ) / fee[2] * fee[3] 

// 기본시간이내 : 기본요금 
// 출차 시간 max = 23:59
// 분 단위는 올림

// 주차시간 구하기 
// records.forEach(r => r.split(' ')

// log 객체에 {차번호: 시간} 저장
// IN 이면 + (24시간(분) - 입차시간)
// OUT이면 -(1430 - 출차시간)
// 24시간 = 1440분

// ex) 05:34 (05 * 60) + 34 = 334

 

 

 

 

 

 

 

반응형