알고리즘/프로그래머스

[프로그래머스] 다리를 지나는 트럭 - Java

반응형

https://programmers.co.kr/learn/courses/30/lessons/42583

 

코딩테스트 연습 - 다리를 지나는 트럭

트럭 여러 대가 강을 가로지르는 일차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다. 다리에는 트럭이 최대 bridge_length대 올라갈

programmers.co.kr


문제

문제 설명

트럭 여러 대가 강을 가로지르는 일차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다. 다리에는 트럭이 최대 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 이하입니다.

입출력 예

brideg_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

풀이

풀이 과정

트럭들을 순차적으로 비교하고 처리하기 위해 선입선출 구조를 가진 큐를 이용하고
다리위에 올라가있는 트럭들의 무게의 합을 저장할 변수를 선언

public int solution(int bridge_length, int weight, int[] truck_weights) {
	int answer = 0;
        
	Queue<Integer> q = new LinkedList<Integer>();
	int sum = 0; // 다리를 건너는 트럭들의 무게 합
}

 

트럭 배열에서 순서대로 하나씩 꺼내오며 크게 두가지 상황으로 나누어서 비교

  • 큐가 비어 있을 때 ( 다리를 건너는 트럭이 없을 때 )
  • 큐가 비어 있지 않을 때 ( 다리 위에 트럭이 있을 때 )

우선 큐가 비어 있는 경우는 큐에 다음 트럭을 추가하고 그 무게를 sum에 더해주고 건너는 시간을 증가 시킨다

반대로 큐가 비어있지 않은 경우에는 다시 세가지 경우로 나눌 수 있는데

  1. 큐의 사이즈와 다리의 길이가 같을 때 ( 다리 위에 트럭이 다 올라가 있을 때 )
  2. 다음 트럭이 최대 무게를 초과할 때
  3. 다음 트럭이 최대 무게 이내일 때

큐의 사이즈와 다리의 길이가 같을 때는 가장 앞에 있는 트럭이 다리를 통과해 나갈 차례 이므로 큐에서 처음 값을 빼고 그만큼의 무게를 무게의 합에서 빼준다

만약, 다음 트럭이 최대 무게를 초과할 때는 트럭의 무게 대신 0을 넣어주고 시간만 증가 시킨다

반대로, 다음 트럭이 최대 무게 이내일 경우에는 다음 트럭의 무게를 큐와 다리위 트럭무게의 합에 더해주고 시간도 증가시킨다

for(int t : truck_weights) {
			
	while(true) {
		//큐가 비어있다면 다음 트럭 삽입
		if(q.isEmpty()) {
			q.offer(t);
			sum += t;
			answer++;
			break;
		}
		//큐가 비어있지 않을 때
		else {
			//큐의 사이즈와 다리의 길이가 같다면 큐에서 큐에서 처음 값을 빼고 무게 합 -
		    if(q.size() == bridge_length) {
			sum -= q.poll();
		    }
			//다음 트럭이 최대 무게 초과
			else if(sum + t > weight) {
				q.offer(0);
				answer++;
			}
			//다음 트럭이 최대 무게 이내
			else {
				q.offer(t);
				sum += t;
				answer++;
				break;
			}
		}
	}
}

 

이렇게 반복을 진행하면 마지막 트럭이 다리에 올라간 시점에 반복문이 종료되게 되는데 지금까지 걸린 시간에서 마지막 트럭이 통과하는 시간, 즉 다리의 길이만큼을 더해주면 모든 트럭이 다리를 건너는 총 시간이 된다

//걸린 시간 + 마지막 트럭의 통과시간(다리의 길이)
return answer + bridge_length;

 

최종 코드

import java.util.LinkedList;
import java.util.Queue;

class Solution {
    public int solution(int bridge_length, int weight, int[] truck_weights) {
        int answer = 0;
        
		Queue<Integer> q = new LinkedList<Integer>();
		int sum = 0; // 다리를 건너는 트럭들의 무게 합
		
		for(int t : truck_weights) {
			
			while(true) {
				//큐가 비어있다면 다음 트럭 삽입
				if(q.isEmpty()) {
					q.offer(t);
					sum += t;
					answer++;
					break;
				}
				//큐의 사이즈와 다리의 길이가 같다면 큐에서 큐에서 처음 값을 빼고 최대 무게 -
				else if(q.size() == bridge_length) {
					sum -= q.poll();
				}
				//큐가 비어있지 않을 때
				else {
					//다음 트럭이 최대 무게 초과
					if(sum + t > weight) {
						q.offer(0);
						answer++;
					}
					//다음 트럭이 최대 무게 이내
					else {
						q.offer(t);
						sum += t;
						answer++;
						break;
					}
				}
			}
		}
		
		//걸린 시간 + 마지막 트럭의 통과시간(다리의 길이)
		return answer + bridge_length;
	}
}