본문 바로가기

알고리즘/프로그래머스_Python

[Programmers] 주차 요금 계산

https://school.programmers.co.kr/learn/courses/30/lessons/92341?language=python3 

 

프로그래머스

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

programmers.co.kr

 

삽질🔨

조건을 잘못 이해해서 오래 걸렸다 ㅠㅠ

- 하룻동안 주차 시간을 합산해서 요금을 한 번에 계산해야 하는데 출차 할 때마다 요금을 구했다.

그리고 디버깅에 오랜 시간을 썼는데, 바로 fees[2] 이렇게 인덱싱을 해서 써야 하는데 fees 그냥 이렇게 써버린 것 ...

최대한 실수를 줄이고 디버깅을 빨리빨리 할 수 있어야 한다.

그리고 출차한 차량을 딕셔너리에서 삭제해버렸는데, 그러면 for문을 돌고있는 딕셔너리의 크기가 변해서 에러가 난다.

이점 꼭 유의하자.

 

그래서 코드는?

# 입차된 후 출차 내역 없다면, 23:59에 출차된 것으로 간주
# 기본 시간 이하라면, 기본 요금
# 기본 시간 초과하면, 기본 요금 + 초과 단위 시간(올림)마다 단위 요금
# 딕셔너리?
# fees : 기본 시간, 기본 요금, 단위 시간, 단위 요금

def solution(fees, records):
    answer = []
    carNum_hour = {} # 차량 번호, 입차 시간
    carNum_fee = {} # 차량 번호, 총 요금
    carNum_mins = {} # 차량 번호, 총 주차 시간
    
    def calcMins(in_hour, out_hour): # 주차 시간 계산하는 함수
        in_h, in_min = in_hour.split(":")
        out_h, out_min = out_hour.split(":")
        hs = int(out_h)-int(in_h)
        mins = int(out_min)-int(in_min)
        return hs*60 + mins
        
    def calcFee(total): # 주차 요금 계산하는 함수
        if total <= fees[0]: # 기본 시간 이하라면
            return fees[1]
        else: 
            if (total-fees[0])%fees[2] == 0:
                return fees[1] + int((total-fees[0])/fees[2])*fees[3]
            else:
                return fees[1] + int((total-fees[0])/fees[2])*fees[3] + fees[3]
        
    for record in records:
        hour, carNum, inout = record.split(" ")
        if (carNum_hour.get(carNum) == None) or len(carNum_hour[carNum]) == 0: # 입차
            carNum_hour[carNum] = [hour]
        else: # 출차
            in_hour = carNum_hour[carNum]
            parking_mins = calcMins(in_hour[0], hour)
            if carNum_mins.get(carNum) == None:
                carNum_mins[carNum] = parking_mins
            else:
                carNum_mins[carNum] += parking_mins
            carNum_hour[carNum] = [] # 출차한 차 입차내역 딕셔너리에서 삭제
    
    # 출차처리 안된 차량 23:59으로 출차 처리
    for carNum, hour in carNum_hour.items():
        if len(hour) != 0:
            parking_mins = calcMins(hour[0], "23:59")
            if carNum_mins.get(carNum) == None:
                carNum_mins[carNum] = parking_mins
            else:
                carNum_mins[carNum] += parking_mins
    
    for carNum, total_mins in carNum_mins.items():
        fee = calcFee(total_mins)
        carNum_fee[carNum] = fee
        
    carNum_fee = dict(sorted(carNum_fee.items(), key=lambda x:int(x[0])))
    
    return list(carNum_fee.values())

풀긴 풀었는데, 코드가 너~~~무 지저분하다.

 

그럼 고수의 풀이를 한 번 봐보자.

from math import ceil
def solution(fees, records):
    answer = []
    default_time, default_fee, unit_time, unit_fee = fees
    parking = {}
    using_time = {}
    for record in records:
        time, number, io = record.split()
        hour, minute = map(int,time.split(":"))
        time = hour * 60 + minute
        if io == "IN":
            parking[number] = time
        elif io == "OUT":
            if number in using_time:
                using_time[number] += (time - parking[number])
            else:
                using_time[number] = time - parking[number]
            del parking[number]
    for number, time in parking.items():
        if number in using_time:
            using_time[number] += 1439 - time
        else:
            using_time[number] = 1439 - time
    for number, time in sorted(using_time.items(), key = lambda x:x[0]):
        answer.append(default_fee+ max(0,ceil((time-default_time)/unit_time)) * unit_fee)
    return answer

 

배운점

- 맨날 딕셔너리를 사용할 때 키 값이 딕셔너리에 이미 있는지 확인할 때 if dictName.get(keyName) == None: 이런 식으로 썼었는데

if keyName in dictName: 이런 식으로 해줄 수도 있다 !!

- 시간을 저장할 때 그냥 int값으로 저장하면 된다. (23:59)도 int값으로 만들어놓으면 훨씬 코드가 간결해진다.