본문 바로가기
파이썬/코딩테스트

[파이썬] 코딩테스트 10 구현_주차문제

by nemonemonemo 2025. 8. 6.

문제

  • 2022년 카카오 기출 3번
  • 정답률 73%
 

프로그래머스

SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr


문제 설명

주차장의 요금표와 차량이 들어오고(입차) 나간(출차) 기록이 주어졌을 때, 차량별로 주차 요금을 계산하려고 합니다. 아래는 하나의 예시를 나타냅니다.

  • 요금표

기본 시간(분) 기본 요금(원) 단위 시간(분) 단위 요금(원)

180 5000 10 600
  • 입/출차 기록

시각(시:분) 차량 번호 내역

05:34 5961 입차
06:00 0000 입차
06:34 0000 출차
07:59 5961 출차
07:59 0148 입차
18:59 0000 입차
19:09 0148 출차
22:59 5961 입차
23:00 5961 출차
  • 자동차별 주차 요금

차량 번호 누적 주차 시간(분) 주차 요금(원)

0000 34 + 300 = 334 5000 + ⌈(334 - 180) / 10⌉ x 600 = 14600
0148 670 5000 +⌈(670 - 180) / 10⌉x 600 = 34400
5961 145 + 1 = 146 5000
  • 어떤 차량이 입차된 후에 출차된 내역이 없다면, 23:59에 출차된 것으로 간주합니다.
    • 0000번 차량은 18:59에 입차된 이후, 출차된 내역이 없습니다. 따라서, 23:59에 출차된 것으로 간주합니다.
  • 00:00부터 23:59까지의 입/출차 내역을 바탕으로 차량별 누적 주차 시간을 계산하여 요금을 일괄로 정산합니다.
  • 누적 주차 시간이 기본 시간이하라면, 기본 요금을 청구합니다.
  • 누적 주차 시간이 기본 시간을 초과하면, 기본 요금에 더해서, 초과한 시간에 대해서 단위 시간 마다 단위 요금을 청구합니다.
    • 초과한 시간이 단위 시간으로 나누어 떨어지지 않으면, 올림합니다.
    • ⌈a⌉ : a보다 작지 않은 최소의 정수를 의미합니다. 즉, 올림을 의미합니다.

주차 요금을 나타내는 정수 배열 fees, 자동차의 입/출차 내역을 나타내는 문자열 배열 records가 매개변수로 주어집니다. 차량 번호가 작은 자동차부터 청구할 주차 요금을 차례대로 정수 배열에 담아서 return 하도록 solution 함수를 완성해주세요.

제한사항

  • fees의 길이 = 4
    • fees[0] = 기본 시간(분)
    • 1 ≤ fees[0] ≤ 1,439
    • fees[1] = 기본 요금(원)
    • 0 ≤ fees[1] ≤ 100,000
    • fees[2] = 단위 시간(분)
    • 1 ≤ fees[2] ≤ 1,439
    • fees[3] = 단위 요금(원)
    • 1 ≤ fees[3] ≤ 10,000
  • 1 ≤ records의 길이 ≤ 1,000
    • records의 각 원소는 "시각 차량번호 내역" 형식의 문자열입니다.
    • 시각, 차량번호, 내역은 하나의 공백으로 구분되어 있습니다.
    • 시각은 차량이 입차되거나 출차된 시각을 나타내며, HH:MM 형식의 길이 5인 문자열입니다.
      • HH:MM은 00:00부터 23:59까지 주어집니다.
      • 잘못된 시각("25:22", "09:65" 등)은 입력으로 주어지지 않습니다.
    • 차량번호는 자동차를 구분하기 위한, `0'~'9'로 구성된 길이 4인 문자열입니다.
    • 내역은 길이 2 또는 3인 문자열로, IN 또는 OUT입니다. IN은 입차를, OUT은 출차를 의미합니다.
    • records의 원소들은 시각을 기준으로 오름차순으로 정렬되어 주어집니다.
    • records는 하루 동안의 입/출차된 기록만 담고 있으며, 입차된 차량이 다음날 출차되는 경우는 입력으로 주어지지 않습니다.
    • 같은 시각에, 같은 차량번호의 내역이 2번 이상 나타내지 않습니다.
    • 마지막 시각(23:59)에 입차되는 경우는 입력으로 주어지지 않습니다.
    • 아래의 예를 포함하여, 잘못된 입력은 주어지지 않습니다.
      • 주차장에 없는 차량이 출차되는 경우
      • 주차장에 이미 있는 차량(차량번호가 같은 차량)이 다시 입차되는 경우

입출력 예

fees records result

[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]
[120, 0, 60, 591] ["16:00 3961 IN","16:00 0202 IN","18:00 3961 OUT","18:00 0202 OUT","23:58 3961 IN"] [0, 591]
[1, 461, 1, 10] ["00:00 1234 IN"] [14841]

입출력 예 설명

입출력 예 #1

문제 예시와 같습니다.

입출력 예 #2

  • 요금표

기본 시간(분) 기본 요금(원) 단위 시간(분) 단위 요금(원)

120 0 60 591
  • 입/출차 기록

시각(시:분) 차량 번호 내역

16:00 3961 입차
16:00 0202 입차
18:00 3961 출차
18:00 0202 출차
23:58 3961 입차
  • 자동차별 주차 요금

차량 번호 누적 주차 시간(분) 주차 요금(원)

0202 120 0
3961 120 + 1 = 121 0 +⌈(121 - 120) / 60⌉x 591 = 591
  • 3961번 차량은 2번째 입차된 후에는 출차된 내역이 없으므로, 23:59에 출차되었다고 간주합니다.

입출력 예 #3

  • 요금표

기본 시간(분) 기본 요금(원) 단위 시간(분) 단위 요금(원)

1 461 1 10
  • 입/출차 기록

시각(시:분) 차량 번호 내역

00:00 1234 입차
  • 자동차별 주차 요금

차량 번호 누적 주차 시간(분) 주차 요금(원)

1234 1439 461 +⌈(1439 - 1) / 1⌉x 10 = 14841
  • 1234번 차량은 출차 내역이 없으므로, 23:59에 출차되었다고 간주합니다. 

풀이

  • 문제 체크
    • 요금표의 구성
      • 기본요금, 요금, 추가 시간 단위, 추가시간 단위별 요금
      • 리스트의 4개 원소로 담겨있다.
    • 입출 로그 기록
      • 입출에 대한 이벤트 기준으로 작성된 로그 → 차량 중심의 기록이 아님 (그래서 차량 중심으로 취합하는 과정이 필요하겠군)
      • 개별 원소 → 개별 이벤트
        • “언제” “누가” “In/Out”
        • 출차 정보가 있을수도 있고 없을 수도 있다
        • case by case를 잘 생각해야함 (출차 없는 경우 23:59분에 출차라고 생각)
        • 언제 - HH:MM (범위: 00:00~23:59)
        • 누가 - [0-9]{4}, \d{4}, DDDD
          • 0~9의 숫자가 4번 반복됨
        • 내역 - IN/OUT 영문자열
        • 값의 순서 → 시간순서대로 찍혀있음 (차량 순서 아님→ 그래서 내가 따로 모아야할지도)
        • → 그 이상 지저분한 케이스 없으니, 제시한 룰만 잘 해
    • 요금 정산 : 중간 정산이 아니라 일관정산 = 누적 시간 계산 (분 단위)
      • 기준이 무엇인가? → 그날 누적 분 이용시간
        • case1) 누적 시간 ≤기본이용시간 ⇒ 기본요금
        • case2) 누적 시간 > 기본 이용 시간 ⇒ 기본 요금 + 추가요금

  • 제출
    • (이름, 성적) ---> 이름을 사전 순,,,친구들의 성적만 제출하세요!!
    • (차량번호, 지불요금) --> 차량번호 정렬 ----> 요금만 제출 리스트로!

  • *** 입출차 기록에 대해서 빠진 경우 꼭!! 신경써서 코드 짜세요!!!
  • *** 최종 요금 계산 시에 추가시간 처리(올림) 잘 하세요!!!!!!!!

  • 주어진 정보 어떻게 처리? → 자료형 dict
    • key: 차량번호
    • value : 차량에 대한 입출력 기록들을 리스트로
      • 앞의 문제와 유사하게 세팅
        • 1번 중복 이슈,,,
        • 3번 출차기록이 없는 경우
  • 입력에 대한 정보를 처리 HH:MM(입력) → 분 (처리 기준)
    • 여러번 사용될 수 있어서 함수로 만들고자 함
    • 입력 범위
      • 00:00 ~ 23:59
      • 0분 ~ 1439분 [분 단위로 00:00을 기준 0분으로 해서 분 단위로 환산]
      • "06:00 0000 IN" // 06:00 시간에 0000차가 입차!!! → 0000: [ (6*60, IN) ]
      • "06:34 0000 OUT" // 06:34 시간에 0000차가 출차!!! → 0000: [ (660, IN) , (660+34, OUT) ] ⇒ 660+34 - 66 = 34분,,,
      • "18:59 0000 IN" → 0000: [ (660, IN) , (660+34, OUT), (18*60+59, IN) ]
      • 출차 기록 추가할 차량이 있는지 체크!!!
        • 규칙
          • c1 : 로그 기록숫자 홀 ==> (23*60+59,out)
          • 0000: [ (660, IN) , (660+34, OUT), (1860+59, IN),(2360+59,out) ]
          • c2 : 로그 기록숫자 짝수 : 추가 할 일 없음
      • 누적 시간을 계산
        • 0000: [ (360, IN) , (394, OUT), (1139, IN),(1139,out) ]
          • ( 394-360 ) + ( 1439 - 1139)
          • 394 + 1439 - 360 - 1139 = (394 + 1439) - (360+1139)
          • ⇒ 입차시간의 합 - 출차시간의 합
      • 요금 계산
        • --> 기준 시간 넘냐? 안넘냐?
        • ==> 기준 300분 넘었어요!!! --> 추가 요금 계산하자!!
          • (334-300) = 34
          • 34/ 10 = 3.4 -----> 4
          • 30 / 10 = 3 ------> 3
      • m1) 그냥 직접 하기,,, i = 34 if i % 10 == 0: print(i//10) else: print( (i//10) + 1)
      • m2) 파이썬 math 패키지 --> ceil 함수를 사용하면 됨!!!!
      • m3) skill + 테크닉!! ) 지식적인 부분!!!! 음수를 나눗셈으로 활용!!! +sql i = 34 -(int((-i//10)))

  • 시간 변환 함수
    • “6:30” → 390분
    • 입력: HH:MM 5글자 문자열
    • 할일 : 00:00 기준 0분으로 해서 얼마나 분으로 지났는지 계산
    • 출력: 00:00 기준 지나간 “분”
      def convert_h_to_m(time_HHMM):
      		h_part, m_part = time_HHMM.split(":") #"6:30" -> ["60,"30"]
      		total_min = int(h_part) * 60 + int(m_part)
          return total_min
      ​

코드 풀이

def convert_h_to_m(time_HHMM):
		h_part, m_part = time_HHMM.split(":") #"6:30" -> ["60,"30"]
		total_min = int(h_part) * 60 + int(m_part)
    return total_min

def solution(fees, records):
    answer = []
    ##--------------------------------------
    # 1) fees 주차장 요금 기준 정보 : 기본시간/요금/추가단위/추가요금
    # ==> 정수, 리스트 : 파이썬 멀티 할당
    base_time, base_cost, add_time, add_cost = fees

    # 2) 입력 주차 로그 처리 records ==> 마라톤/신고문제 유사
    #-> Dict를 사용해서 처리 (개취)
    #    k: 자동차번호 --> 정렬 기준으로 사용
    #    v: 차량 입출 정보들 --> [], 1개 값(HH:MM은 분 환원한 정보, 상태)
    #--> 신고 문제는 모든 유저들을 리스트업하고 시작
    #==> 이 문제는 모든 차량이 아니라 그냥 오는 차량 별로 작업할 예정
    park_dict+{}
    #주차 로그 표를 보면서 정리하겠다 (차 기준)
    for record in records :
        #1개 주차 로그에 대한 처리
        #2-1)'05:34 5961 IN' --> 시간, 차번호, 상태
        park_time, car_id, status = record.split(" ")
        #'05:34 5961 IN' --> ['05:34', '5961', 'IN']

        #2-2) 정리의 기준 차 번호 key -> 숫자화(나중에 정렬할 때 사용해야되니까)
        #"5961" --> int("5961") --> 5961
        #"0000" --> int("0000") --> 0 (제로패딩)
        car_id = int(car_id)

        #2-3) 정리를 차 번호 기준에 맞춰서 value 추가 
        #'05:34 IN' --> 앞쪽 시간에 대한 것을 함수 : (60*5+34, IN)
        car_record = [convert_h_to_m(park_time), status]

        #2-4) 실제 등록 처리
        #case1) 이미 등록된 차 번호
        if car_id in park_dict:
            park_dict[car_id].append(car_record)
            #5961 : [[394, "IN"]] --> 5961 : [[394, "IN"], [400, "OUT"]]
        #case2) 신규 등록된 차 번호
        else:
            park_dict[car_id] = [car_record]
            #5961 : [[394, "IN"]]
    #-------> 받은 입출 기록에 대한 1차 정리

    #누적시간에 + 비용도 계산 ==> 출차 정보가 누락된 것은 그것도 추가해야함
    #===> 계산용 dict (key : 차번호, value: 누적요금): 정렬 + 출력
    #cp1 : 출차 정보 처리 -> 만약 출차 정보 없다면? => (1459, "OUT") 넣어줘야
    #cp2 : 누적 시간 계산
    #   cp2-1) 기본 요금만 (기본 시간 이하)
    #   cp2-2) 추가 요금 발생 (기본 시간 1분이라도 부과한다)
    #       ---> 초과 시간이 나눠떨어지는 경우 : 몫 그대로
    #       ---> 초과 시간이 나눠 떨어지지 않는 경우 : (몫 + 1)
    car_dict = {} #k: 차번호, v: 누적요금
    # 차 별로 주차 기록을 바탕으로 누적 요금 계산!!!
    for car, logs ini park_dict.items(): #k, v로 돌리려고
        #car : 0
        #logs : [[300, "IN"], [334, "OUT"], [1139, "IN"]]
        #==> IN :[300, 1139]
        #    OUT : [334] +///[1149]
        out_time_list = [ m for m, sta in logs if sta == "OUT"] #LC #[334]
        in_time_list = [ m for m, sta in logs if sta == "IN"] #LC #[300, 1139]

        #들어왔는데 나간 정보가 없는 차량에 대해서 예외처리
        #--> logs 원소 수 : 홀수 ==> 추가 처리
        if len(logs) % 2 ==1:
            #출차 기록이 없는 : [334]-->[334,1149]
            out_time_list.append(convert_h_to_m("23:59"))
            #[334]-->[334,1149]
        #----in : [300,1139], out = [334, 1149]

        # 차량별로 누적시간(분)
        total_min = sum(out_time_list) - sum(in_time_list)
        #(334+1149) - (300+1139) = (334-300) + (1149-1139)

        #요금 계산 과정
        if total_min <= base_time:
            #기본 시간 이내 ==> 기본 요금만
            car_dict[car] = base_cost
        else: #추가 요금 발생하는 경우
            cost = 0
            cost += base_cost # 일단 기본요금 부과
            totla_min -= base_time #누적시간 = 기존 누적시간 - 기본시간
            #--> 추가 요금 계산 => 나눠떨어지느냐? 나눠떨어지지 않느냐?
            if total_min % add_time ==0 :
                cost += (total_min//add_time)* add_cost
                car_dict[cat] = cost
            else:
                cost += ((total_min//add_time)+1)* add_cost
                car_dict[cat] = cost
    #--> 롤링 : 차 번호 --> 유니크
    #car_dict = {0:14600, 148:34400, 5961:5000}

    # 4) 최종 답안지 제출
    #==> 정렬(key값 차량번호 오름차순으로)
    #--> 출력물 : 오로지 최종 요금만 리스트로 출력!
    car_dict = dict(sorted(car_dict.items())) # dict()로 감싸는 거 굳이?
    answer = list(car_dict.values())

    return answer
#코드만 정리
def convert_h_to_m(time_HHMM):
    h_part, m_part = time_HHMM.split(":") # "06:30" --> ["06","30"]
    total_min = int(h_part) * 60 + int(m_part)
    return total_min

def solution(fees, records):
    answer = []
    base_time, base_cost, add_time, add_cost  = fees
    park_dict = {}
    for record in records:
        park_time, car_id, status = record.split(" ")
        car_id = int(car_id)
        car_record = [ convert_h_to_m(park_time), status ]
        if car_id in park_dict:
            park_dict[car_id].append( car_record )
        else:
            park_dict[car_id] = [car_record] # *** 주의!!!!! ****
    car_dict = {}# k:차번호, v:누적요금
    for car, logs in park_dict.items(): # k,v
        out_time_list = [m for m, sta in logs if sta =="OUT" ] # [334]
        in_time_list  = [m for m, sta in logs if sta =="IN" ] # [300,1139]
        if len(logs) % 2 == 1:
            out_time_list.append( convert_h_to_m("23:59"))
        total_min = sum(out_time_list) - sum(in_time_list)
        if total_min <= base_time:
            car_dict[car] = base_cost
        else: # 추가 요금 발생하는 경우..
            cost = 0
            cost += base_cost # 일단 기본 요금 부과!!!
            total_min -= base_time # 누적시간 = 기존 누적시간 - 기본 시간
            if total_min % add_time ==0:
                cost += (total_min // add_time) * add_cost
                car_dict[car] = cost
            else:
                cost += ((total_min // add_time)+1) * add_cost
                car_dict[car] = cost
    car_dict = dict(sorted( car_dict.items())) # ---> 굳이;;;;
    answer = list(car_dict.values())
    return answer
  • 왜 이 문제를 3번에 배치 했을까
    • 1번과 3번 스타일 거의 유사하기는 함
    • 3번에 좀 더 고려할 사항이 있다(여러 프로세스가 있다)
    • 지식적인 부분보다는 기본적인 상황들을 복잡한 문제에서 이해하고 꼼꼼하게 잘 하는가를 봄
    • 더 복잡해질 수는 있음…