티스토리 뷰

https://school.programmers.co.kr/learn/courses/30/lessons/92341

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

🤔 해결방법

1. 입출차 기록을 자동차 번호 기준으로 오름차순 정렬하고 자동차 번호만 추출한다.

2. for문을 돌며 자동차 번호 별 입차, 출차 시간을 계산하는데, 출차까지 한 경우와 입차만 한 경우로 나눠 계산한다.

3. 기본 시간을 기준으로 주차 요금을 계산하고 answer에 차례로 push 한다.

 

 

🔑 풀이

먼저 입출차 기록을 관리하기 쉽게 이중 배열로 저장했다.

그리고 차량 번호가 작은 자동차부터 청구할 주차 요금을 차례대로 출력해야 하기 때문에 자동차 번호를 기준으로 오름차순 정렬을 했다.

  // 이중 배열로 저장
    let arr = [];
    for (let i = 0; i < records.length; i++) {
      const [time, number, act] = records[i].split(" ");
      arr.push([time, Number(number), act]);
    }

    // 기록 오름차순 정렬
    const record = arr.sort((a, b) => a[1] - b[1]);

 

또한 각 기록을 자동차 별로 확인하기 위해 자동차 번호만 중복 제거하여 추출해 오름차 순으로 cars 배열에 담았다.

  // 차량 번호만 추출 및 오름차순 정렬
    const cars = Array.from(new Set(arr.map((item) => item[1]))).sort(
      (a, b) => a - b
    );

 

이후 누적 주차 시간을 for문을 돌며 계산한다.

이 때, 출차까지 한 경우와 입차만 한 경우로 나누어 계산해야 한다.

 

이미 오름차순으로 정렬했기 때문에 출차까지 한 경우는 그 다음 기록의 차 번호가 같을 것이다.

이런 경우 출차에 해당하는 다음 기록의 시간과 입차에 해당하는 현재 기록 사이의 시간을 구한다.

시간에는 60을 곱하고 거기에 분을 더해 총 시간을 분으로 환산하는 방법을 썼는데 string으로 들어가 있기에 number로 바꿔서 계산해야 한다.

이렇게 되면 출차까지 한 경우는 계산이 완료되었으니 i에 2를 더해 그 다음 입차 기록으로 넘어가게 해주면 된다.

 

만약 출차 기록이 없는 경우, 즉 입차만 한 경우는 입차 기록부터 23시59분까지의 시간을 계산해주면 된다.

23시에 60을 곱하고 59분을 더해주면 1439분이 되므로 1439에서 입차 시각을 빼주고 i를 1증가시켜 다음 기록으로 넘어간다.

// 출차도 한 경우
  if (i < record.length - 1 && record[i + 1][1] === car) {
    minutes +=
      Number(record[i + 1][0].slice(0, 2)) * 60 +
      Number(record[i + 1][0].slice(3, 5)) -
      (Number(record[i][0].slice(0, 2)) * 60 +
        Number(record[i][0].slice(3, 5)));
    i += 2;
  // 입차만 한 경우
  } else {
    minutes +=
      1439 -
      (Number(record[i][0].slice(0, 2)) * 60 +
        Number(record[i][0].slice(3, 5)));
    i++;
  }

 

이후 기본 시간을 기준으로 주차 요금을 계산하고 answer에 차례로 push하여 출력하면 된다.

// 주차 요금 계산
  if (minutes < fees[0]) {
    answer.push(fees[1]);
  } else {
    let fee = fees[1] + Math.ceil((minutes - fees[0]) / fees[2]) * fees[3];
    answer.push(fee);
  }

 

최종 코드는 다음과 같다.

function solution(fees, records) {
    let answer = [];

    // 이중 배열로 저장
    let arr = [];
    for (let i = 0; i < records.length; i++) {
      const [time, number, act] = records[i].split(" ");
      arr.push([time, Number(number), act]);
    }
    // 기록 오름차순 정렬
    const record = arr.sort((a, b) => a[1] - b[1]);

    // 차량 번호만 추출 및 오름차순 정렬
    const cars = Array.from(new Set(arr.map((item) => item[1]))).sort(
      (a, b) => a - b
    );

    // 누적 주차 시간 계산
    for (let car of cars) {
      let minutes = 0;
      for (i = 0; i < record.length; ) {
        if (record[i][1] === car) {
          // 출차도 한 경우
          if (i < record.length - 1 && record[i + 1][1] === car) {
            minutes +=
              Number(record[i + 1][0].slice(0, 2)) * 60 +
              Number(record[i + 1][0].slice(3, 5)) -
              (Number(record[i][0].slice(0, 2)) * 60 +
                Number(record[i][0].slice(3, 5)));
            i += 2;
          // 입차만 한 경우
          } else {
            minutes +=
              1439 -
              (Number(record[i][0].slice(0, 2)) * 60 +
                Number(record[i][0].slice(3, 5)));
            i++;
          }
        } else {
          i++;
        }
      }
      // 주차 요금 계산
      if (minutes < fees[0]) {
        answer.push(fees[1]);
      } else {
        let fee = fees[1] + Math.ceil((minutes - fees[0]) / fees[2]) * fees[3];
        answer.push(fee);
      }
    }

    return answer;
  }

 

시간을 분으로 환산하는 부분이 반복이 많아 더 좋은 방법을 생각해봤다.

다음과 같이 함수를 따로 생성해서 사용한다면 훨씬 가독성이 좋아질 것 같다.

  // 시간을 분으로 변환
    const timeToMinutes = (time) => {
      const [hour, minute] = time.split(":");
      return Number(hour) * 60 + Number(minute);
    };

 

댓글