본문 바로가기

개발자 세릴리/코딩테스트

[Softeer] Java - level2 문제풀이(회의실 예약)

728x90
반응형

 

softeer 회의실 예약(Java)

[문제]

회사에는 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을 출력한다.

 

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

 

[풀이]

- 회의실 이름은 List<String> 으로 입력 받아서 가장 먼저 정렬을 해두었습니다.(Collection.sort() 이용)

- 회의실 예약은 HashMap 을 이용해서 입력 받았습니다. 이때 HashMap 의 key 는 room 이름이 들어갈 String, value 는 예약 시간이 들어갈 List<Integer> 으로 입력 받았습니다. 미리 오름차순으로 정렬해둔 회의실 이름을 key 값으로 저장하고, 이후 예약 내용을 저장 받았습니다. 

- 예약시간은 String으로 연결 시킨 값을 Integer 형으로 바꿔서 저장했습니다. 시간 순서대로 정렬하는데 이용하기 위해서 입니다.

- 이후 각 room 이름 순서대로 테스트 케이스라고 생각하고 반복문을 썼습니다. 또 가능한 시간을 담을 availableTime 을 선언해서 사용했습니다.

1. 예약이 없는 경우 : 09-18 가능

2. 예약이 한 건 있는 경우 : 예약건 앞만 비거나, 앞 뒤로 비거나, 뒤만 비는 세 가지 경우의 수 가능

3. 예약건이 여러 건인 경우 : 예약건의 시작 시간과 종료 시간을 확인하며 빈 시간을 확인하며 availableTime에 저장해갑니다.

- 마지막 출력은 availableTime 의 size()가 0이면 Not available을, 아니라면 가능한 시간이 짝수로만 시간이 저장되기 때문에 2건씩 출력해 줍니다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] input = br.readLine().split(" ");
        int N = Integer.parseInt(input[0]);
        int M = Integer.parseInt(input[1]);
        List<String> room = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            room.add(br.readLine());
        }
        Collections.sort(room);
        HashMap<String, List<Integer>> reservation = new HashMap<>();
        for (int i = 0; i < N; i++) {
            reservation.put(room.get(i), new ArrayList<>());
        }
        for (int i = 0; i < M; i++) {
            String[] temp = br.readLine().split(" ");
            String tempTime = temp[1] + temp[2];
            reservation.get(temp[0]).add(Integer.parseInt(tempTime));
        }
        int start;
        int end;
        boolean available = true;
        for (int i = 0; i < N; i++) {
            List<Integer> availableTime = new ArrayList<>();
            List<Integer> checkTime = reservation.get(room.get(i));
            Collections.sort(checkTime);
            /*예약이 하나도 들어오지 않은 경우*/
            if (checkTime.size() == 0) {
                availableTime.add(9);
                availableTime.add(18);
            }
            /*예약이 한 건만 들어온 경우*/
            for (int j = 0; j < checkTime.size(); j++) {
                start = checkTime.get(j) / 100;
                end = checkTime.get(j) % 100;
                if (checkTime.size() == 1) {
                    if (start < 9) {
                        available = false;
                    } else if (start > 9) {
                        if (end < 18) {
                            availableTime.add(9);
                            availableTime.add(start);
                            availableTime.add(end);
                            availableTime.add(18);
                        } else {
                            availableTime.add(9);
                            availableTime.add(start);
                        }
                    } else {
                        if (end >= 18) {
                            available = false;
                        } else {
                            availableTime.add(end);
                            availableTime.add(18);
                        }
                    }
                /*예약이 2건 이상 들어온 경우*/
                } else {
                    /*첫 번째 예약 건*/
                    if (j == 0) {
                        if (start < 9) {
                            available = false;
                        } else if (start > 9) {
                            availableTime.add(9);
                            availableTime.add(start);
                            availableTime.add(end);
                        } else {
                            availableTime.add(end);
                        }
                    /*마지막 예약 건*/
                    } else if (j == checkTime.size() - 1) {
                        if (end < 18) {
                            if (availableTime.get(availableTime.size() - 1) > start) {
                                available = false;
                            } else if (availableTime.get(availableTime.size() - 1) < start) {
                                availableTime.add(start);
                                availableTime.add(end);
                                availableTime.add(18);
                            } else {
                                availableTime.remove(availableTime.size() - 1);
                                availableTime.add(end);
                                availableTime.add(18);
                            }
                        } else if (end > 18) {
                            available = false;
                        } else {
                            if (availableTime.get(availableTime.size() - 1) > start) {
                                available = false;
                            } else if (availableTime.get(availableTime.size() - 1) < start) {
                                availableTime.add(start);
                            } else {
                                availableTime.remove(availableTime.size() - 1);
                            }
                        }
                    /*중간 예약 건*/
                    } else {
                        if (availableTime.get(availableTime.size() - 1) > start) {
                            available = false;
                        } else if (availableTime.get(availableTime.size() - 1) < start) {
                            availableTime.add(start);
                            availableTime.add(end);
                        } else {
                            availableTime.remove(availableTime.size() - 1);
                            availableTime.add(end);
                        }
                    }
                }
            }
            System.out.println("Room " + room.get(i) + ":");
            if (!available || availableTime.size() == 0) {
                System.out.println("Not available");
            } else {
                System.out.println(availableTime.size() / 2 + " available:");
                for (int j = 0; j < availableTime.size(); j += 2) {
                    if (availableTime.get(j) < 10) {
                        System.out.print("0" + availableTime.get(j) + "-");
                        System.out.println(availableTime.get(j + 1));
                    } else {
                        System.out.print(availableTime.get(j) + "-");
                        System.out.println(availableTime.get(j + 1));
                    }
                }
            }
            if (i != room.size() - 1) {
                System.out.println("-----");
            }
            available = true;
        }
        br.close();
    }
}

 

문제에서 주어지는 테스트 케이스가 2개 뿐이지만, 소프티어 문제들의 특징은 답안을 제출했을 때 더 많은 테스트 케이스를 실행시켜 정답 판별을 합니다. 그래서 예시 사항 중 회의실 예약이 겹치는 경우와 9-18시를 벗어나는 예약이 있는 경우를 전부 생각하며 작성했더니 코드가 엄청 길어졌습니다ㅠㅠ. 덕분에 한 번만에 정답을 맞출 수 있었지만 아무래도 코드 길이(깔끔함)에 아쉬움이 남습니다.

이틀 동안 문제가 풀리지 않아서 검색을 했을 때 파이썬 코드로 푼 해결법만 확인할 수 있었습니다. 단순히 보기엔 파이썬 코드들은 아주 간단해서 더 아쉬움이 남았지 않나 싶습니다. 파이썬의 자료구조에 대해 잘은 모르지만, 개인적으로 Java 자료구조도 데이터를 다루기에 좀 더 다양해졌으면 하는 바람입니다.

제가 잘 이용할 줄 모르는 것일 수도 있지만.... 스택을 썼을 땐 자료를 출력할 때 아쉽고.... 배열을 쓰면 정렬(sort)할 때 아쉽고....

여러모로 자료구조를 바꿔가며 해결해야하는 부분이 많아서 아직은 너무 어렵습니다ㅠㅠ

 

혹시라도 저처럼 java로 문제를 푸는 분이 계시다면 도움이 되셨으면 좋겠고, 더 좋은 해결법이 있다면 알려주세요! 감사히 배우겠습니다 :)

728x90
반응형