CODING TEST/Programmers

[ JavaScript ] 프로그래머스 level2 42583번 다리를 지나는 트럭

JUNGY00N 2024. 1. 23. 16:13

다리를 지나는 트럭 #42583

프로그래머스 알고리즘 고득점 Kit > 스택/큐 > level2 다리를 지나는 트럭

더보기

문제 설명

트럭 여러 대가 강을 가로지르는 일차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다. 다리에는 트럭이 최대 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_lengthweighttruck_weightsreturn
2 10 [7,4,5,6] 8
100 100 [10] 101
100 100 [10,10,10,10,10,10,10,10,10,10] 110

처음에 문제가 이해가 가지 않아서 여러번 읽어보고, 출처도 읽어보았다. 

프로그래머스 내의 설명이 조금 부족한 것 같기도 했다. 

출처를 읽었을 떄 이해한 것은 bridge_length는  트럭 하나가 건너려면 걸리는 시간을 뜻하는 것 같았다. 

 

첫번째 입출력 예를 그림/표로 그려본다면 아래와 같다. 

나의 풀이

function solution(bridge_length, weight, truck_weights) {
  let sec = 0; // 총 걸리는 시간

  const size = truck_weights.length; // 전체 트럭의 수

  const wait = truck_weights; // 대기 중인 트럭 배열
  const bridge = []; // 다리 위인 트럭 배열 [weight,지나온 길이]
  const finish = []; // 다리를 벗어난 트럭 배열

  let weightOnBridge = 0; // 다리 위 트럭들의 무게 합

  // 다리를 벗어난 트럭의 갯수가 총 트럭의 갯수보다 작을 때만 아래를 반복함
  while (finish.length < size) {
    // 다리의 가장 앞에 있는 트럭이 지나온 길이가 다리의 길이와 같으면 finish로 이동
    if (bridge.length > 0 && bridge[0][1] == bridge_length) {
      weightOnBridge -= bridge[0][0];
      finish.push(bridge.shift());
    }

    // 다리 위 무게 + 들어갈 트럭의 무게가 한계값보다 작거나 같으면
    // 다리에 트럭을 push하고, wait 배열에서 제거
    if (weightOnBridge + wait[0] <= weight) {
      bridge.push([wait[0], 0]);
      weightOnBridge += wait[0];
      wait.shift();
    }

    sec++; // 시간이 1초 증가되면
    bridge.forEach((el) => el[1]++); // 다리 위 트럭들이 지나온 길이가 1 증가한다.
  }

  return sec;
}
  • 총 걸리는 시간 변수 sec
  • 전체 트럭의 개수 size 
  • 대기 중인 트럭 배열 wait
  • 다리 위인 트럭 배열 bridge
    • bridge 배열의 값들은 [weight,지나온 길이] 형태로 push된다. 
  • 다리를 벗어난 트럭 배열 finish
  • 다리 위 트럭들의 무게의 합 weightOnBridge

를 선언한다.

  • 다리를 벗어난 트럭의 개수가 총 트럭의 수와 같으면 모든 트럭이 다리를 벗어난 상태이므로 그때까지 반복한다.
  • 다리 위 트럭 중 가장 앞에 있는 트럭이 지나온 길이가 다리의 길이와 같으면 다 건넌 것이므로 finsish 배열로 이동한다. 
  • 다리 위 무게에 들어갈 트럭의 무게 값을 더한 것이 한계값을 넘지 않으면
    bridge에 트럭을 넣고, wait에서 제거한다. 
  • 시간을 1초 증가시키고,
  • 다리 위 트럭들의 지나온 길이도 1씩 증가시킨다. 

다른 풀이

function solution(bridge_length, weight, truck_weights) {
  let sec = 0; // 걸리는 시간
  let bridge = [[0, 0]]; // 다리 위 트럭 [무게, 빠져나가는 시간]
  let weightOnBridge = 0; // 다리 위 총 무게

  while (bridge.length > 0 || truck_weights.length > 0) {
    // 다리의 첫 트럭의 빠져나가가는 시간이 현재 시간과 같으면 다리에서 제거
    if (bridge[0][1] === sec) {
      weightOnBridge -= bridge.shift()[0];
    }

    // 다리 위 무게 + 들어갈 트럭이 한계 무게를 넘지 않으면
    // 다리에 트럭을 추가
    if (weightOnBridge + truck_weights[0] <= weight) {
      weightOnBridge += truck_weights[0];
      bridge.push([truck_weights.shift(), sec + bridge_length]);
    } else {
      // 트럭을 더 넣을 수 없으면, 현재 시간을 다리의 첫 트럭이 빠져나가는 시간으로 jump
      // 1을 빼주는 이유는, if문 밖에서 시간 증가가 이루어지기 때문
      if (bridge[0]) sec = bridge[0][1] - 1;
    }

    sec++; // 시간 1초 증가
  }

  return sec;
}

 나의 풀이와의 차이점들은

  • finish 배열 x 
  • bridge 배열의 값들의 두번째 값을 지난 다리의 길이가 아닌, 빠져나가는 시간으로 저장한 것 
    • 지나온 다리의 길이로 넣었을 때는 시간이 지날때마다 하나씩 증가시켜주었어야 했음
  • 트럭을 더 넣을 수 없을 때 계속 시간을 1씩 증가시키면 루프를 돌지 않고, 현재 시간을 jump함

 

트럭의 수가 늘어날때마다 효율성의 차이가 크게 드러난다. 

나의 풀이에서는 걸리는 초만큼 무조건 while을 돌게되는 반면에, 

다른 풀이에서는 걸리는 시간을 jump했기 때문이다.