[소프티어] 회의실 예약 | JavaScript

예구·2023년 8월 7일
0

Softeer

목록 보기
5/13
post-thumbnail

문제출처

1. 문제

회사에는 N개의 회의실이 있다. 수많은 팀이 모여 토론하고 업무를 처리하기 위해서는 회의실이 필수적이다.

내부망에 아주 간단한 회의실 예약 시스템이 있지만 편의성이 매우 떨어진다. 단순히 예약된 회의의 목록만 표시되기 때문에, 방 별로 비어 있는 시간이 언제인지를 확인하기가 힘든 것이다. 당신은 이를 직접 해결해 보기로 마음 먹었다.

회의실 이용 규칙은 다음과 같다:

  • 회의실은 9시부터 18시까지만 사용 가능하다. 모든 회의의 시간은 이 안에 완전히 포함되어야 한다.

  • 회의는 정확히 한 회의실을 연속한 일정 시간 동안만 점유한다. 즉 각 회의는 (회의실, 시작 시각, 종료 시각)의 정보로 나타낼 수 있다.

  • 회의의 시작과 종료 시각은 시(時, hour) 단위로만 설정 가능하다. 같은 회의실을 사용하는 회의 시간은 서로 겹칠 수 없다. 여기서 겹친다는 것은, 두 회의 모두에 포함되는 시간이 1시간 이상 존재한다는 것을 의미한다. 예를 들어, 10시-12시의 회의와 11시-13시의 회의는 겹치는데, 11시-12시의 시간이 두 회의 모두에 포함되기 때문이다.

  • 한 회의가 끝나는 시각에, 같은 회의실에서 다른 회의가 시작하는 것은 허용된다. 이 경우 두 회의가 겹치지 않기 때문이다.

  • 길이가 0인 회의, 즉 시작 시각과 종료 시각이 동일한 회의는 예약된 바 없으며, 새롭게 잡을 수도 없다.

이미 예약된 M개의 회의에 대한 정보가 주어지면, 회의실별로 비어 있는 시간대를 정리해 출력하는 프로그램을 작성해 보자. 구체적인 형식은 아래를 참고하시오.

제약조건

1 ≤ N ≤ 50
1 ≤ M ≤ 100

회의실의 이름은 영문 알파벳 소문자로만 이루어져 있으며 길이는 1 이상 10 이하이다.
주어지는 모든 시각은 9 이상 18 이하이다.
회의의 시작 시각은 회의의 종료 시각을 1시간 이상 앞선다.

입력형식

첫째 줄에 회의실의 수와 예약된 회의의 수를 나타내는 정수 N과 M이 공백을 사이에 두고 주어진다.
이어 N개의 줄에는 각 회의실의 이름이 주어진다.
이어 M개의 줄에는 각 회의가 배정된 회의실의 이름 r과 시작 시각 s, 그리고 종료 시각 t가 공백을 사이에 두고 주어진다.

출력형식

각 회의실에 대한 정보를 회의실 이름의 오름차순으로 출력한다.

각 회의실에 대한 정보는 다음과 같다.
첫째 줄에는 { Room 회의실이름: } (중괄호 제외)을 출력한다.
둘째 줄에는 예약가능 시간을 출력한다.

  • 예약 가능한 시간대의 개수를 n이라고 할 때, { n available: } (중괄호 제외)을 출력하고, 뒤따른 n개의 줄에 예약 가능한 시간대를 { 09-18 } (하이픈 한개, 중괄호 제외)형태로 출력해야 한다. 한 자리 수의 경우 앞에 0을 붙여 두 자리 수로 만들어야 함에 유의하라.

  • 예약 가능한 시간이 없다면, Not available을 출력한다.

각 회의실에 대한 정보 사이에는 ----- (하이픈 다섯 개)로 구분선이 출력되어야 한다.

입력예제1

3 7
grandeur
avante
sonata
sonata 14 16
grandeur 11 12
avante 15 18
sonata 10 11
avante 9 12
grandeur 16 18
avante 12 15

출력예제1

Roomavante:
Notavailable
-----
Roomgrandeur:
2available:
09-11
12-16
-----
Roomsonata:
3available:
09-10
11-14
16-18



2. 풀이

고려해야 할 것도 많고, 처리해야 할 것도 많은 문제다.

회의실별로 길이가 9인 배열을 만들어서 시간대별 예약 여부를 관리했고, 모든 회의실과 각 배열을 객체로 관리했다.
배열의 길이가 9인 이유는 회의 시작 시간인 9시 ~ 17시까지를 체크하기 위함이다.

시간대별 예약 여부를 관리한 배열과 입력예제1 중 sonata와 grandeur는 다음과 같다.

예시 설명 사진

시간대별로 예약이 되어 있으면 1을 더해줬다.
여기까지는 무난했으나, 출력할 부분을 처리하는 게 시간이 많이 걸렸다.

예약 가능 시간을 출력하는 부분을 정리하면 다음과 같다.

  • 예약 가능 시간의 시작 시간을 저장하기 위해 start라는 변수를 -1로 초기화했다.
  • 해당 회의실의 시간대별 예약 여부를 저장한 reserved_check의 길이만큼 돌면서 start값을 찾는다.
  • start를 찾고, 현재 값이 1이라면 예약 가능한 시간대가 끝나는 부분이므로 available_times(예약 가능한 시간을 저장하는 배열)에 넣어준다. 그리고 start-1로 다시 만들어주고, cnt(예약 가능한 시간대 개수)에 1을 더해준다.
  • start를 찾았지만 회문이 끝났다면 reserved_check의 마지막 값이 0인 경우이므로 available_times에 해당 시간부터 18시까지를 넣어준다.

이 부분만 빨리 해결되었으면 빨리 풀었을텐데 생각보다 시간을 많이 잡아먹은 문제다.
전체 코드는 아래와 같다.

const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

let array = []; // input값 저장할 배열
let rooms = {}; // 회의실 현황

rl.on("line", (line) => {
  array.push(line.trim());
}).on("close", () => {
  // 전체 회의실 수, 예약 건수
  [total_rooms, reserved_cnt] = array[0].split(" ").map(Number);
  let rooms_name = []; // 회의실 이름만 저장

  // 회의실 개수만큼 순회하면서 회의실 이름 배열과 회의실 예약 현황 객체에 넣어주기
  for (let i = 1; i <= total_rooms; i++) {
    let room_name = array[i];
    rooms_name.push(room_name);
    rooms[room_name] = new Array(9).fill(0);
  }

  // 회의실 이름 오름차순 정렬
  rooms_name.sort();

  // 각 회의실의 예약된 시간에 +1하기
  for (let i = total_rooms + 1; i < array.length; i++) {
    let [room_name, start_time, end_time] = array[i].split(" ");
    for (let j = parseInt(start_time) - 9; j < parseInt(end_time) - 9; j++) {
      rooms[room_name][j] += 1;
    }
  }

  // 출력하기
  for (let i = 0; i < total_rooms; i++) {
    let name = rooms_name[i]; // 회의실 이름

    // 1) 회의실 이름 출력
    console.log(`Room ${name}:`);

    // 2) 예약 가능 시간 출력
    let reserved_check = rooms[name]; // 해당 회의실의 사용 가능 여부
    let cnt = 0; // 예약 가능한 시간대 개수
    let start = -1; // 0이 시작하는 시간
    let available_times = []; // 예약 가능한 시간 저장하는 배열

    for (let i = 0; i < reserved_check.length; i++) {
      // 예약 가능한 시간대 시작 시간 찾기
      if (reserved_check[i] === 0 && (i === 0 || reserved_check[i - 1] === 1))
        start = i + 9;
		
      // 예약 가능한 시간대 추가 및 cnt에 1 더하기
      if (reserved_check[i] === 1 && start !== -1) {
        available_times.push(
          `${String(start).padStart(2, "0")}-${String(i + 9).padStart(2, "0")}`
        );
        start = -1;
        cnt++;
      }
    }

    // 배열의 마지막 원소가 0인 경우 처리
    if (start !== -1) {
      available_times.push(`${String(start).padStart(2, "0")}-18`);
      cnt++;
    }

    // 예약 가능한 시간이 없는 경우
    if (!cnt) console.log("Not available");
    // 예약 가능한 시간이 있는 경우
    else {
      console.log(`${cnt} available:`);
      available_times.forEach((e) => console.log(e));
    }

    // 3) 구분선 출력
    if (i !== total_rooms - 1) console.log("-----");
  }

  process.exit();
});
profile
우당탕탕 FE 성장기

0개의 댓글