문제
수강신청의 마스터 김종혜 선생님에게 새로운 과제가 주어졌다.
김종혜 선생님한테는 Si에 시작해서 Ti에 끝나는 N개의 수업이 주어지는데, 최소의 강의실을 사용해서 모든 수업을 가능하게 해야 한다.
참고로, 수업이 끝난 직후에 다음 수업을 시작할 수 있다. (즉, Ti ≤ Sj 일 경우 i 수업과 j 수업은 같이 들을 수 있다.)
수강신청 대충한 게 찔리면, 선생님을 도와드리자!
입력
첫 번째 줄에 N이 주어진다. (1 ≤ N ≤ 200,000)
이후 N개의 줄에 Si, Ti가 주어진다. (0 ≤ Si < Ti ≤ 109)
출력
강의실의 개수를 출력하라.
💡풀이
강의 시작 시간과 종료 시간을 담은 Lecture 클래스를 하나 선언하고, 이를 강의 시작 시간을 기준으로 오름차순 정렬, 만약 시작 시간이 같다면 종료 시간을 기준으로 오름차순 정렬할 수 있도록 compareTo메서드를 작성한다.
class Lecture implements Comparable<Lecture>{
int start;
int end;
public Lecture(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public int compareTo(Lecture o) {
if(this.start == o.start )
return this.end - o.end;
return this.start - o.start;
}
}
처음에는 이를 강의 한 개의 종료 시간을 잡고, 나머지 강의들의 시작 시간과 비교하여 종료 시간보다 같거나 크면 지우는 방식으로 풀이를 했지만, 역시나 시간 초과가 발생하였다. 찾아보니, ArrayList의 경우 get()메서드는 $O(1)$의 시간 복잡도를 가지지만, add()메서드와 remove()메서드의 경우 $O(N)$의 시간 복잡도를 가진다고 한다. 이 때문에 시간초과가 발생했지 않을까 싶다.
그래서, 종료 시간을 기준으로 하는 우선순위 큐를 이용했다.
Lecture로 이루어진 ArrayList를 순회하며 비교하는데,
1. 우선, 첫 번째 강의를 우선순위 큐에 넣어준다.
2. 그리고 그 다음 Lecture 리스트부터 순회를 시작하며, 우선순위 큐에 있는 종료 시간과 비교한다.
3. 만약, 이때 우선순위 큐의 peek의 종료 시간이 순회 중인 Lecture 리스트의 시작 시간보다 크다면, 그 강의는 첫 번째 강의가 있던 강의실에 넣을 수 없다는 것을 의미한다. 따라서, 새로운 강의실을 사용해야하기 때문에, 우선순위 큐에 새로 넣어준다.
4. 그 경우가 아니라면, peek에 해당하는 강의의 강의실을 이어 사용할 수 있다는 의미이므로, peek에 해당하는 강의가 끝났으니 우선순위 큐에서 제거해준다.
5. 결국 최종적으로 순회를 마쳤을 때, 우선순위 큐의 크기가 사용할 강의실의 개수가 된다.
전체적인 코드는 다음과 같다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
class Lecture implements Comparable<Lecture>{
int start;
int end;
public Lecture(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public int compareTo(Lecture o) {
if(this.start == o.start )
return this.end - o.end;
return this.start - o.start;
}
}
public class Q11000 {
public static ArrayList<Lecture> list = new ArrayList<>();
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int N = Integer.parseInt(br.readLine());
for(int i=0;i<N;++i){
String str = br.readLine();
st = new StringTokenizer(str, " ");
list.add(new Lecture(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken())));
}
Collections.sort(list);
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.offer(list.get(0).end);
for(int i=1;i<N;++i){
if(list.get(i).start>=pq.peek()){
pq.poll();
}
pq.offer(list.get(i).end);
}
System.out.println(pq.size());
}
}
'알고리즘 > BOJ' 카테고리의 다른 글
[BOJ] 1987 : 알파벳(Java) (0) | 2022.11.17 |
---|---|
[BOJ] 16174 : 점프왕 쩰리(Large)(Java) (0) | 2022.11.13 |
[BOJ] 5052 : 전화번호 목록(Java) (0) | 2022.10.01 |
[BOJ] 9657 : 돌 게임3(Java) (0) | 2022.09.05 |
[BOJ] 1992 : 쿼드트리(Java) (1) | 2022.08.28 |