주차 요금 계산 문서의 문제 1 풀이 코드다. if __name__ == "__main__": 아래가 자체 테스트다.

"""주차 요금 계산 (프로그래머스 92341) 풀이와 검증."""
import math
import random


def solution(fees, records):
    base_t, base_fee, unit_t, unit_fee = fees

    def minutes(hhmm):
        h, m = map(int, hhmm.split(":"))
        return h * 60 + m

    in_time = {}
    total = {}
    for r in records:
        t, car, kind = r.split()
        if kind == "IN":
            in_time[car] = minutes(t)
        else:
            total[car] = total.get(car, 0) + minutes(t) - in_time.pop(car)
    for car, t in in_time.items():
        total[car] = total.get(car, 0) + minutes("23:59") - t
    answer = []
    for car in sorted(total):
        over = max(0, total[car] - base_t)
        answer.append(base_fee + (over + unit_t - 1) // unit_t * unit_fee)
    return answer


def by_minutes(fees, records):
    """1분마다 주차장 안에 있는 차를 센다. [들어온 분, 나간 분) 동안 1분씩."""
    events = {}
    for r in records:
        t, car, kind = r.split()
        events.setdefault(int(t[:2]) * 60 + int(t[3:]), []).append((car, kind))
    inside, used = set(), {}
    for minute in range(24 * 60):
        for car, kind in events.get(minute, []):
            if kind == "IN":
                inside.add(car)
                used.setdefault(car, 0)
            else:
                inside.discard(car)
        for car in inside:
            if minute < 23 * 60 + 59:
                used[car] += 1
    out = []
    for car in sorted(used):
        u = used[car]
        fee = fees[1]
        if u > fees[0]:
            fee += math.ceil((u - fees[0]) / fees[2]) * fees[3]
        out.append(fee)
    return out


def rand_records(rng):
    cars = [f"{rng.randint(0, 9999):04d}" for _ in range(rng.randint(1, 4))]
    evs = []
    for c in set(cars):
        pts = sorted(rng.sample(range(0, 1439), rng.choice([1, 2, 3, 4, 5, 6])))
        for i, p in enumerate(pts):
            evs.append((p, c, "IN" if i % 2 == 0 else "OUT"))
    evs.sort()
    # 같은 분에 같은 차가 두 번 나오지 않게 sample로 뽑았다
    return [f"{p // 60:02d}:{p % 60:02d} {c} {k}" for p, c, k in evs]


if __name__ == "__main__":
    assert solution([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]
    assert solution([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]
    assert solution([1, 461, 1, 10], ["00:00 1234 IN"]) == [14841]
    assert solution([60, 1000, 10, 100], ["08:00 1111 IN", "10:15 1111 OUT", "22:00 2222 IN"]) == [1800, 1600]
    rng = random.Random(92341)
    for _ in range(2000):
        fees = [rng.randint(1, 300), rng.randint(0, 5000), rng.randint(1, 60), rng.randint(1, 1000)]
        recs = rand_records(rng)
        assert solution(fees, recs) == by_minutes(fees, recs), (fees, recs)
    print("ALL CHECKS PASSED")