
문제집에 난이도가 다른 문제가 여러 개 있는데 그 중 가장 어려운 문제 혹은 가장 쉬운 문제를 추천해주는 문제
문제 특성 상 자유롭게 정렬, 넣었다 빼기가 가능해야 하므로 덱을 사용해야 할 것 같았는데 생각해보니 덱은 양 끝에서만 가능하기 때문에 힙을 사용해야 한다. 최대힙, 최소힙으로 최댓값, 최소값을 쉽게 찾을 수 있다.
먼저 힙은 완전이진트리를 따른다 - 부모 노드가 자식 노드를 최대 두개까지 가지고 있으면서 마지막 레벨을 제외한 나머지 노드가 완전히 채워진 형태의 트리
최대 힙 : 부모 노드가 자식 노드보다 항상 클 경우
- 삽입의 경우 맨 끝에 삽입되어 부모 노드보다 클 경우 루트쪽으로 계속 교환하며 올라감
- 삭제의 경우 루트 노드가 삭제되고 가장 마지막 노드가 루트 노드로 올라온 후 제자리를 찾아갈 수 있도록 교환하며 내려감
- 최소 힙도 반대로 연산 가능
StringTokenizer를 사용해 입력을 쪼개서 받는다. 구분자를 따로 지정해주지 않으면 공백이 기본 구분자
문제번호
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
public class 문제_추천_시스템_Version_1 {
static class Problem {
int num, level;
public Problem(int num, int level) {
this.num = num;
this.level = level;
}
}
public static void main(String[] args) throws IOException{
//입력을 많이 받기 때문에 속도가 빠른 버퍼리더 선택
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
StringBuffer sb = new StringBuffer();
PriorityQueue<Problem> maxHip = new PriorityQueue<>((a, b) -> {
//먄약 문제의 난이도가 같으면
if (a.level == b.level) {
//번호가 큰것부터 내림차순 정렬
return b.num - a.num;
} else {
return b.level - a.level;
}
});
PriorityQueue<Problem> minHip = new PriorityQueue<>((a, b) -> {
if (a.level == b.level) {
return a.num - b.num;
} else {
return a.level - b.level;
}
});
Map<Integer, Integer> problemMap = new HashMap<>();
int N = Integer.parseInt(bf.readLine());
for (int i=0; i<N; i++) {
//문자를 쪼개서 받기 위해 사용
StringTokenizer st = new StringTokenizer(bf.readLine());
int P = Integer.parseInt(st.nextToken());
int L = Integer.parseInt(st.nextToken());
Problem problem = new Problem(P, L);
maxHip.add(problem);
minHip.add(problem);
problemMap.put(P, L);
}
int M = Integer.parseInt(bf.readLine());
for (int i=0; i<M; i++) {
StringTokenizer st = new StringTokenizer(bf.readLine());
String command = st.nextToken();
if (command.equals("add")) {
int P = Integer.parseInt(st.nextToken());
int L = Integer.parseInt(st.nextToken());
Problem problem = new Problem(P, L);
maxHip.add(problem);
minHip.add(problem);
problemMap.put(P, L);
} else if (command.equals("solved")) {
int P = Integer.parseInt(st.nextToken());
problemMap.remove(P);
} else if (command.equals("recommend")) {
int x = Integer.parseInt(st.nextToken());
if (x == 1) {
while (true) {
Problem top = maxHip.peek();
//문제가 해시맵에 존재하고 해시맵에 있는 문제의 난이도가 최대힙 루트 노드의 난이도와 같다면
if (problemMap.containsKey(top.num) && problemMap.get(top.num) == top.level) {
//최대힙 루트 노드 출력
sb.append(top.num).append("\n");
break;
}
maxHip.poll();
}
} else {
while (true) {
Problem top = minHip.peek();
if (problemMap.containsKey(top.num) && problemMap.get(top.num) == top.level) {
sb.append(top.num).append("\n");
break;
}
minHip.poll();
}
}
}
}
System.out.println(sb);
}
}