[백준 - 21939][GOLD 4][해설 X] - 문제 추천 시스템 Version 1 (JAVA)

728x90

 

문제


tony9402는 최근 깃헙에 코딩테스트 대비 문제를 직접 뽑아서 "문제 번호, 난이도"로 정리해놨다.

깃헙을 이용하여 공부하시는 분들을 위해 새로운 기능을 추가해보려고 한다.

만들려고 하는 명령어는 총 3가지가 있다. 아래 표는 각 명령어에 대한 설명이다.

recommend 𝑥   𝑥가 1인 경우 추천 문제 리스트에서 가장 어려운 문제의 번호를 출력한다.
만약 가장 어려운 문제가 여러 개라면 문제 번호가 큰 것으로 출력한다.
 𝑥가 -1인 경우 추천 문제 리스트에서 가장 쉬운 문제의 번호를 출력한다.
만약 가장 쉬운 문제가 여러 개라면 문제 번호가 작은 것으로 출력한다.
add 𝑃 𝐿  추천 문제 리스트에 난이도가 𝐿인 문제 번호 𝑃를 추가한다. (추천 문제 리스트에 없는 문제 번호 𝑃만 입력으로 주어진다. 이전에 추천 문제 리스트에 있던 문제 번호가 다른 난이도로 다시 들어 올 수 있다.)
solved 𝑃 추천 문제 리스트에서 문제 번호 𝑃를 제거한다. (추천 문제 리스트에 있는 문제 번호 𝑃만 입력으로 주어진다.)

명령어 recommend는 추천 문제 리스트에 문제가 하나 이상 있을 때만 주어진다.

명령어 solved는 추천 문제 리스트에 문제 번호가 하나 이상 있을 때만 주어진다.

위 명령어들을 수행하는 추천 시스템을 만들어보자.

 

 입력


첫 번째 줄에 추천 문제 리스트에 있는 문제의 개수 𝑁 가 주어진다.

두 번째 줄부터 𝑁+1줄까지 문제 번호 𝑃와 난이도 𝐿가 공백으로 구분되어 주어진다.

 𝑁+2줄은 입력될 명령문의 개수 𝑀이 주어진다.

그 다음줄부터 𝑀개의 위에서 설명한 명령문이 입력된다.

 

출력


recommend 명령이 주어질 때마다 문제 번호를 한 줄씩 출력한다. 최소 한번의 recommend 명령어가 들어온다.

 

해결 코드


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());

        //가장 어려운 문제 순으로 정렬
        PriorityQueue<Problem> largestPQ = new PriorityQueue<>(Collections.reverseOrder());
        //가장 쉬운 문제 순으로 정렬
        PriorityQueue<Problem> smallestPQ = new PriorityQueue<>();

        //문제 번호당 난이도를 저장한 배열(최대 문제 번호 값 100,000)
        int[] levels = new int[100_001];

        //기본 추천 문제 리스트 초기화
        for(int i=0;i<N;i++){
            StringTokenizer st = new StringTokenizer(br.readLine());

            int num = Integer.parseInt(st.nextToken());
            int level = Integer.parseInt(st.nextToken());
            levels[num] = level;

            Problem problem = new Problem(num,level);

            largestPQ.add(problem);
            smallestPQ.add(problem);
        }

        Set<String> solveSet = new HashSet<>();

        int M = Integer.parseInt(br.readLine());

        //추가 문제 더함
        for(int i=0;i<M;i++){
            StringTokenizer st = new StringTokenizer(br.readLine());
            String command = st.nextToken();

            //문제를 추가하는 경우 해당 번호의 난이도를 갱신하고 각 최대/최소 문제 큐에 문제 추가
            if(command.equals("add")){
                int num = Integer.parseInt(st.nextToken());
                int level = Integer.parseInt(st.nextToken());

                levels[num] = level;
                Problem problem = new Problem(num,level);

                largestPQ.add(problem);
                smallestPQ.add(problem);
            }
            //문제를 추천하는 경우 번호-난이도의 키를 이용해 이미 풀어낸 문제를 제거
            else if(command.equals("recommend")){
                int val = Integer.parseInt(st.nextToken());

                if(val == 1){
                    //번호-난이도로 키 생성
                    String key = largestPQ.peek().num +"-"+largestPQ.peek().level;

                    //이미 푼 문제를 제거
                    while(solveSet.contains(key)){
                        largestPQ.poll();
                        key = largestPQ.peek().num +"-"+largestPQ.peek().level;
                    }
                    System.out.println(largestPQ.peek().num);
                }else{
                    //번호-난이도로 키 생성
                    String key = smallestPQ.peek().num +"-"+smallestPQ.peek().level;

                    //이미 푼 문제를 제거
                    while(solveSet.contains(key)){
                        smallestPQ.poll();
                        key = smallestPQ.peek().num +"-"+smallestPQ.peek().level;
                    }
                    System.out.println(smallestPQ.peek().num);
                }
            }else{
                int num = Integer.parseInt(st.nextToken());

                //문제-난이도 키를 등록
                solveSet.add(num+"-"+levels[num]);
            }
        }
    }
}

class Problem implements Comparable<Problem>{
    int num;
    int level;

    public Problem(int num, int level){
        this.num = num;
        this.level = level;
    }

    @Override
    public int compareTo(Problem o) {
        if(this.level == o.level){
            return this.num - o.num;
        }
        return this.level - o.level;
    }
}
 

 

실행 결과


 


  • 방문배열이 너무 커지면 set을 이용해 생성하자 
  • 데이터의 고유키가 무엇인지 확인해보자. 복합키의 경우의 수도 있다.