다리를 지나는 트럭
문제 링크
문제 설명
트럭 여러 대가 강을 가로지르는 일 차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다.
다리에는 트럭이 최대 bridge_length대 올라갈 수 있으며, 다리는 weight 이하까지의 무게를 견딜 수 있습니다. 단, 다리에 완전히 오르지 않은 트럭의 무게는 무시합니다.
예를 들어, 트럭 2대가 올라갈 수 있고 무게를 10kg까지 견디는 다리가 있습니다. 무게가 [ 7, 4, 5, 6 ] kg인 트럭이 순서대로 최단 시간 안에 다리를 건너려면 다음과 같이 건너야 합니다.
경과 시간 | 다리를 지난 트럭 | 다리를 건너는 트럭 | 대기 트럭 |
0 | [] | [] | [ 7, 4, 5, 6 ] |
1 ~ 2 | [] | [ 7 ] | [ 4, 5, 6 ] |
3 | [ 7 ] | [ 4 ] | [ 5, 6 ] |
4 | [ 7 ] | [ 4, 5 ] | [ 6 ] |
5 | [ 7, 4 ] | [ 5 ] | [ 6 ] |
6 ~ 7 | [ 7, 4, 5 ] | [ 6 ] | [] |
8 | [ 7, 4, 5, 6 ] | [] | [] |
따라서, 모든 트럭이 다리를 지나려면 최소 8초가 걸립니다.
solution 함수의 매개면수로 다리에 올라갈 수 있는 트럭 수 bridge_length, 다리가 견딜 수 있는 무게 weight, 트럭 별 무게 truck_weights가 주어집니다. 이때 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 return 하도록 solution 함수를 완성하세요.
제한 조건
- bridge_length는 1 이상 10,000 이하입니다.
- weight는 1 이상 10,000 이하입니다.
- truck_weights의 길이는 1 이상 10,000 이하입니다.
- 모든 트럭의 무게는 1 이상 weight 이하입니다.
입출력 예
bridge_length | weight | truck_weights | return |
2 | 10 | [ 7, 4, 5, 6 ] | 8 |
100 | 100 | [ 10 ] | 101 |
100 | 100 | [ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ] | 110 |
해결 과정
0. 반환할 값인 경과 시간 sec, 대기 중인 트럭에서 1순위인 트럭 standby_truck, 다리를 지나고 있는 트럭들의 전체 무게 bridge_weight를 선언해 주고 시간복잡도를 줄이기 위해 다리를 건너고 있는 트럭과 대기 중인 트럭의 list를 queue로 만들어줍니다.
💡 liist의 pop(0)의 시간복잡도는 O(n)이고, pop() 시간복잡도는 O(1)이다.
1. 다리를 건너고 있는 트럭과 대기 중인 트럭이 없을 때까지 while loop을 돌려줍니다.
2. while이 진행될 때마다 경과시간을 1씩 증가시켜 줍니다.
3. 다리를 건너고 있는 트럭이 있다면 꺼내주기 위해 while loop을 돌려 확인합니다.
- 3-A. 다리를 건너는 데 걸리는 시간인 다리 길이와 ( 현재 경과 시간 - 트럭이 건너기 시작한 시점의 경과 시간 )이 같다면 꺼내줍니다.
- 3-B. 트럭을 꺼냈으니 다리를 지나고 있는 트럭들의 전체 무게도 감소시킵니다.
- 3-C. 꺼낼 트럭이 없다면 다리를 꺼내주기 위한 while loop을 종료합니다.
4. 대기 중인 트럭이 없거나 ( 다리를 지나고 있는 트럭들의 전체 무게 + 대기 중인 트럭에서 1순위 트럭 )이 무게 기준을 초과했다면 추가로 트럭을 다리 위로 보내지 않습니다.
- 4-A. 대기 중인 트럭 중에서 1순위를 다리 위로 보내고 현재 경과시간도 같이 기록합니다.
- 4-B. 다리를 지나고 있는 트럭들의 전체 무게에 현재 올라간 트럭의 무게를 더해줍니다.
- 4-C. 대기 중인 트럭 중에서 1순위 변수를 초기화해 줍니다.
제출 코드
from collections import deque
def solution(bridge_length, weight, truck_weights):
sec = 0 # "경과 시간"
standby_truck = 0 # "대기 트럭"중 1순위
bridge_weight = 0 # 다리를 지나고 있는 트럭들의 전체 무게
bridge_queue = deque() # "다리를 건너는 트럭"과 경과 시간
truck_queue = deque(truck_weights) # "대기 트럭"
# "다리를 건너는 트럭"과 "대기 트럭"이 있다면 while loop 진행
while bridge_queue or truck_queue:
# 1. 경과 시간을 1씩 증가시켜준다.
sec += 1
# 2. "대기 트럭"이 있고 대기중인 트럭이 없다면 "대기 트럭"중에서 1순위를 꺼내 standby_truck에 담아준다.
if truck_queue and standby_truck == 0:
standby_truck = truck_queue.popleft()
# 3. "다리를 건너는 트럭"이 있다면 while loop
while bridge_queue:
# 3-A.
# '다리를 건너는데 걸리는 시간(다리 길이)'과
# '경과 시간 - 트럭이 건너기 시작한 시간'이 같다면 꺼내준다.
if bridge_length == sec - bridge_queue[0][1]:
truck = bridge_queue.popleft()
# 3-B. 트럭을 꺼냈으니 다리 위 트럭들 무게도 감소시킨다.
bridge_weight -= truck[0]
else:
# 3-C. 꺼낼 트럭이 없다면 while loop을 종료한다.
break
# 4.
# 대기중인 트럭이 없거나
# 다리를 지나고 있는 트럭들의 전체 무게 + "대기 트럭"중에서 1순위 > 무게 기준
# 이라면 추가로 트럭을 다리로 보내지 않는다.
if standby_truck == 0 or bridge_weight + standby_truck > weight:
continue
else:
# 4-A. "대기 트럭"중에서 1순위를 다리에 올리면서 현재의 경과 시간도 같이 담아준다.
bridge_queue.append([standby_truck, sec])
# 4-B. 다리를 지나고 있는 트럭들의 전체 무게를 누적해준다.
bridge_weight += standby_truck
# 4-C. "대기 트럭"중에서 1순위 변수를 초기화 해준다.
standby_truck = 0
return sec
또 다른 풀이
reverse 함수를 활용한 코드
from collections import deque
def solution(bridge_length, weight, truck_weights):
bridge = deque(0 for _ in range(bridge_length))
total_weight = 0
step = 0
truck_weights.reverse()
while truck_weights:
total_weight -= bridge.popleft()
if total_weight + truck_weights[-1] > weight:
bridge.append(0)
else:
truck = truck_weights.pop()
bridge.append(truck)
total_weight += truck
step += 1
step += bridge_length
return step
클래스를 활용한 코드
import collections
DUMMY_TRUCK = 0
class Bridge(object):
def __init__(self, length, weight):
self._max_length = length
self._max_weight = weight
self._queue = collections.deque()
self._current_weight = 0
def push(self, truck):
next_weight = self._current_weight + truck
if next_weight <= self._max_weight and len(self._queue) < self._max_length:
self._queue.append(truck)
self._current_weight = next_weight
return True
else:
return False
def pop(self):
item = self._queue.popleft()
self._current_weight -= item
return item
def __len__(self):
return len(self._queue)
def __repr__(self):
return 'Bridge({}/{} : [{}])'.format(self._current_weight, self._max_weight, list(self._queue))
def solution(bridge_length, weight, truck_weights):
bridge = Bridge(bridge_length, weight)
trucks = collections.deque(w for w in truck_weights)
for _ in range(bridge_length):
bridge.push(DUMMY_TRUCK)
count = 0
while trucks:
bridge.pop()
if bridge.push(trucks[0]):
trucks.popleft()
else:
bridge.push(DUMMY_TRUCK)
count += 1
while bridge:
bridge.pop()
count += 1
return count
'ALGORITHM > Programmers' 카테고리의 다른 글
[Python] 프로그래머스, 괄호 회전하기 Lv.2 (feat.stack, queue, deque, 파이썬) (53) | 2023.03.16 |
---|---|
[Python] 프로그래머스, 더 맵게 Lv.2 (feat.heapq, min heap, 힙, 우선순위 큐, 파이썬) (36) | 2023.03.14 |
[Python] 프로그래머스, 프린터 Lv.2 (feat.Queue, collections, any, all, 파이썬) (37) | 2023.03.08 |
[Python] 프로그래머스, 주식가격 Lv.2 (feat. collections deque, stack, 파이썬) (35) | 2023.03.06 |
[Python] 프로그래머스, 뒤에 있는 큰 수 찾기 Lv.2 (feat.Stack, 시간초과, 파이썬, while문에서 list 활용법) (43) | 2023.03.02 |