[Python] 알고리즘 연습 20 (프로그래머스)

Lake·2024년 5월 31일

Python 문제

목록 보기
20/22
post-thumbnail

주차 요금 계산 (2022 KAKAO BLIND RECRUITMENT)

  • 주차장의 요금표와 차량이 들어오고(입차) 나간(출차) 기록이 주어졌을 때, 차량별로 주차 요금을 계산하려고 합니다. 아래는 하나의 예시를 나타냅니다.
    • 요금표
      기본 시간(분) 기본 요금(원) 단위 시간(분) 단위 요금(원)
      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)에 입차되는 경우는 입력으로 주어지지
                  않습니다.
                - 아래의 예를 포함하여, 잘못된 입력은 주어지지 않습니다
                   - 주차장에 없는 차량이 출차되는 경우
                   - 주차장에 이미 있는 차량(차량번호가 같은 차량)이 다시
                     입차되는 경우

제출한 코드 :

from math import ceil

def time_to_minutes(time):
    """시간을 분으로 변환"""
    h, m = map(int, time.split(':'))
    return h * 60 + m

def calculate_fee(total_time, fees):
    """주차 요금을 계산"""
    base_time, base_fee, unit_time, unit_fee = fees
    if total_time <= base_time:
        return base_fee
    else:
        extra_time = total_time - base_time
        extra_fee = ceil(extra_time / unit_time) * unit_fee
        return base_fee + extra_fee

def solution(fees, records):
    parking_times = {}
    in_parking = {}

    for record in records:
        time, car_number, status = record.split()
        time = time_to_minutes(time)
        
        if status == 'IN':
            in_parking[car_number] = time
        elif status == 'OUT':
            if car_number in in_parking:
                in_time = in_parking.pop(car_number)
                parked_time = time - in_time
                if car_number in parking_times:
                    parking_times[car_number] += parked_time
                else:
                    parking_times[car_number] = parked_time

    # 23:59 출차 처리를 위해
    end_time = time_to_minutes("23:59")
    for car_number, in_time in in_parking.items():
        parked_time = end_time - in_time
        if car_number in parking_times:
            parking_times[car_number] += parked_time
        else:
            parking_times[car_number] = parked_time

    result = []
    for car_number in sorted(parking_times.keys()):
        total_time = parking_times[car_number]
        fee = calculate_fee(total_time, fees)
        result.append(fee)
    
    return result

모음사전 (완전탐색)

  • 사전에 알파벳 모음 'A', 'E', 'I', 'O', 'U'만을 사용하여 만들 수 있는, 길이 5 이하의 모든 단어가 수록되어 있습니다. 사전에서 첫 번째 단어는 "A"이고, 그다음은 "AA"이며, 마지막 단어는 "UUUUU"입니다.

    단어 하나 word가 매개변수로 주어질 때, 이 단어가 사전에서 몇 번째 단어인지 return 하도록 solution 함수를 완성해주세요.

    • 제한사항
      • word의 길이는 1 이상 5 이하입니다.
      • word는 알파벳 대문자 'A', 'E', 'I', 'O', 'U'로만 이루어져 있습니다.

제출한 코드 :

def solution(word):
    # 각 자리별 가중치를 설정
    weights = [781, 156, 31, 6, 1]
    vowels = ['A', 'E', 'I', 'O', 'U']
    
    result = 0
    
    for i, char in enumerate(word):
        # 현재 자리의 단어가 몇 번째 모음인지 확인
        index = vowels.index(char)
        # 각 자리의 위치를 계산해서 더하기
        result += weights[i] * index + 1
    
    return result

뒤에 있는 큰 수 찾기 (연습문제)

  • 정수로 이루어진 배열 numbers가 있습니다. 배열 의 각 원소들에 대해 자신보다 뒤에 있는 숫자 중에서 자신보다 크면서 가장 가까이 있는 수를 뒷 큰수라고 합니다.

    정수 배열 numbers가 매개변수로 주어질 때, 모든 원소에 대한 뒷 큰수들을 차례로 담은 배열을 return 하도록 solution 함수를 완성해주세요. 단, 뒷 큰수가 존재하지 않는 원소는 -1을 담습니다.

    • 제한사항
      • 4 ≤ numbers의 길이 ≤ 1,000,000
        • 1 ≤ numbers[i] ≤ 1,000,000

제출한 코드 :

def solution(numbers):
    n = len(numbers)
    answer = [-1] * n
    stack = []
    
    for i in range(n - 1, -1, -1):
        # 스택이 비어 있지 않고, 현재 숫자가 스택의 top보다 크거나 같으면 pop
        while stack and stack[-1] <= numbers[i]:
            stack.pop()
        
        # 스택이 비어 있지 않다면, top이 뒷 큰수가 됨
        if stack:
            answer[i] = stack[-1]
        
        # 현재 숫자를 스택에 추가
        stack.append(numbers[i])
    
    return answer

롤케이크 자르기 (연습문제)

  • 철수는 롤케이크를 두 조각으로 잘라서 동생과 한 조각씩 나눠 먹으려고 합니다. 이 롤케이크에는 여러가지 토핑들이 일렬로 올려져 있습니다. 철수와 동생은 롤케이크를 공평하게 나눠먹으려 하는데, 그들은 롤케이크의 크기보다 롤케이크 위에 올려진 토핑들의 종류에 더 관심이 많습니다. 그래서 잘린 조각들의 크기와 올려진 토핑의 개수에 상관없이 각 조각에 동일한 가짓수의 토핑이 올라가면 공평하게 롤케이크가 나누어진 것으로 생각합니다.

    예를 들어, 롤케이크에 4가지 종류의 토핑이 올려져 있다고 합시다. 토핑들을 1, 2, 3, 4와 같이 번호로 표시했을 때, 케이크 위에 토핑들이 [1, 2, 1, 3, 1, 4, 1, 2] 순서로 올려져 있습니다. 만약 세 번째 토핑(1)과 네 번째 토핑(3) 사이를 자르면 롤케이크의 토핑은 [1, 2, 1], [3, 1, 4, 1, 2]로 나뉘게 됩니다. 철수가 [1, 2, 1]이 놓인 조각을, 동생이 [3, 1, 4, 1, 2]가 놓인 조각을 먹게 되면 철수는 두 가지 토핑(1, 2)을 맛볼 수 있지만, 동생은 네 가지 토핑(1, 2, 3, 4)을 맛볼 수 있으므로, 이는 공평하게 나누어진 것이 아닙니다. 만약 롤케이크의 네 번째 토핑(3)과 다섯 번째 토핑(1) 사이를 자르면 [1, 2, 1, 3], [1, 4, 1, 2]로 나뉘게 됩니다. 이 경우 철수는 세 가지 토핑(1, 2, 3)을, 동생도 세 가지 토핑(1, 2, 4)을 맛볼 수 있으므로, 이는 공평하게 나누어진 것입니다. 공평하게 롤케이크를 자르는 방법은 여러가지 일 수 있습니다. 위의 롤케이크를 [1, 2, 1, 3, 1], [4, 1, 2]으로 잘라도 공평하게 나뉩니다. 어떤 경우에는 롤케이크를 공평하게 나누지 못할 수도 있습니다.

    롤케이크에 올려진 토핑들의 번호를 저장한 정수 배열 topping이 매개변수로 주어질 때, 롤케이크를 공평하게 자르는 방법의 수를 return 하도록 solution 함수를 완성해주세요.

    • 제한사항
      • 1 ≤ topping의 길이 ≤ 1,000,000
        • 1 ≤ topping의 원소 ≤ 10,000

제출한 코드 :

def solution(topping):
    from collections import defaultdict
    
    left_set = set()
    right_count = defaultdict(int)
    
    # 오른쪽 집합에 모든 토핑의 개수 세기
    for t in topping:
        right_count[t] += 1
    
    # 공평하게 나눌 수 있는 위치의 수
    fair_cuts = 0
    
    # 각 위치에서 자를 때 왼쪽과 오른쪽의 토핑 종류 수를 비교
    for t in topping:
        # 현재 토핑을 왼쪽으로 이동
        left_set.add(t)
        right_count[t] -= 1
        
        # 오른쪽에 더 이상 존재하지 않으면 집합에서 제거
        if right_count[t] == 0:
            del right_count[t]
        
        # 공평하게 나눌 수 있는지 확인
        if len(left_set) == len(right_count):
            fair_cuts += 1
    
    return fair_cuts

숫자 변환하기 (연습문제)

  • 자연수 xy로 변환하려고 합니다. 사용할 수 있는 연산은 다음과 같습니다.

    • xn을 더합니다
    • x에 2를 곱합니다.
    • x에 3을 곱합니다.

       자연수 x, y, n이 매개변수로 주어질 때, xy로 변환하기 위해
       필요한 최소 연산 횟수를 return하도록 solution 함수를 완성해주세요.
       이때 xy로 만들 수 없다면 -1을 return 해주세요.

       - 제한사항
         - 1 ≤ xy ≤ 1,000,000
         - 1 ≤ n < y

제출한 코드 :

from collections import deque

def solution(x, y, n):
    if x == y:
        return 0
    
    # BFS를 위한 큐 초기화: (현재 값, 연산 횟수)
    queue = deque([(x, 0)])
    visited = set()  # 방문한 값을 기록
    
    while queue:
        current, operations = queue.popleft()
        
        # 다음 가능한 연산들을 수행
        for next_value in (current + n, current * 2, current * 3):
            if next_value == y:
                return operations + 1
            if next_value < y and next_value not in visited:
                visited.add(next_value)
                queue.append((next_value, operations + 1))
    
    # 큐를 다 돌 때까지 목표 값을 찾지 못한 경우
    return -1

0개의 댓글