백준 20920 영단어 암기는 괴로워 자바

꾸준하게 달리기~·2023년 6월 19일
0
post-thumbnail

문제는
https://www.acmicpc.net/problem/20920
다음과 같고,
구현 + 정렬 문제인것같다.

나는 정렬 문제를 풀며 약간 외우다시피 했는데,
우리가 아는 알파벳 사전순
숫자 오름차순을 구현하려면
이러한 내용들은 보통 compareTo에서 this 가 먼저 나온다
즉, 아래와 같이 구현하면 된다는 이야기.

//오름차순으로 구현하려면 if 안에서 this를 먼저 써야한다는 말.
if(this.숫자값 > 매개변수.숫자값) return 1;
return -1;

//혹은
return this.숫자값 - 매개변수.숫자값;

아래는 약간 다른데, 우선순위 큐에서는 다익스트라를 생각해보자.
위와 같이 구현하면, 다익스트라에서는 최솟값을 먼저 우선순위로 두고 뽑는다.
그럼 위와 반대로 구현하면, 값이 큰 내용부터 뽑겠네..?
라고 생각하고 풀었다.

먼저 뽑히기 위해서는
1번 우선순위는 자주 나올수록 큐 우선순위가 높다 = 숫자 times가 클수록 먼저 뽑힌다

2번 우선순위는 단어의 길이가 길수록 큐 우선순위가 높다 = String의 length()가 클수록 먼저 뽑힌다.

3번 사전순

public int compareTo (wordBook e) {
            if(this.times == e.times) {
                if(this.word.length() == e.word.length()) {
                    return this.word.compareTo(e.word); //3번 우선순위 알파벳 사전 순
                }
                else {
                    return e.word.length() - this.word.length(); //2번 우선순위, 길수록 큐 우선순위
                }
            }
            return e.times - this.times; //1번 우선순위 자주나올수록 큐 우선순위 (times 클수록)
        }

풀이는 아래와 같다.
각각 주석에 헷갈릴 내용을 설명해놓았다.

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        //우선순위
        //1. 자주 나오는 단어일수록 앞에 배치한다. (횟수에 따라 정렬)
        //2. 해당 단어의 길이가 길수록 앞에 배치한다. (횟수같으면 length() 따라 정렬)
        //3. 알파벳 사전 순으로 앞에 있는 단어일수록 앞에 배치한다 (length() 같으면 기존의 String compareTo에 따라 정렬)

        //첫줄 단어 개수와 제한 길이.
        StringTokenizer st1 = new StringTokenizer(br.readLine());
        int N = Integer.parseInt(st1.nextToken()); //단어 개수
        int M = Integer.parseInt(st1.nextToken()); //제한 길이

        PriorityQueue<wordBook> q = new PriorityQueue<>(); //map을 순회하며 넣어줄 우선순위 Queue
        HashMap<String, Integer> map = new HashMap<>(); //단어를 읽으면서, 해당 단어가 몇번 나왔는지와 함께 저장해줄 map


        for(int i = 0 ; i < N ; i++) {
            String word = br.readLine();

            if(word.length() < M) { //길이 제한 안맞다면, 제끼고
                continue;
            }
            else { //길이 제한 충족할때는
                if(map.containsKey(word)) { //이미 존재하면 갯수 +1 해주고
                    map.replace(word, map.get(word)+1);
                }
                else { //존재하지 않으면 map에 넣어주기
                    map.put(word, 1);
                }
            }
        }

        // 여기까지 오면 map 에 단어와 그 단어의 횟수가 저장됨. 이제 순회하며 해당 내용을 우선순위 큐에 넣을 예정.

        for(Map.Entry<String, Integer> now : map.entrySet()) {
            q.add(new wordBook(now.getKey(), now.getValue()));
        }

        //우선순위 큐이기에, 아래에 작성한 매서드대로 정렬해주니까, Queue의 내용을 뽑아내며 출력하면 된다.

        while(!q.isEmpty()) {
            bw.write(q.poll().word + "\n");
        }
        bw.flush();
        bw.close();

    }

    static class wordBook implements Comparable<wordBook>{
        String word;
        int times;

        public wordBook (String word, int times) {
            this.word = word;
            this.times = times;
        }

        public int compareTo (wordBook e) {
            if(this.times == e.times) {
                if(this.word.length() == e.word.length()) {
                    return this.word.compareTo(e.word); //3번 우선순위
                }
                else {
                    return e.word.length() - this.word.length(); //2번 우선순위, 길수록 큐 우선순위
                }
            }
            return e.times - this.times; //1번 우선순위 자주나올수록 큐 우선순위 (times 클수록)
        }

    }
    

}

아쉬웠던 점은, 큐에 넣으면, 해당 값 꺼내와서 수정하는 로직을 잘 모르겠어서, 따로 해쉬맵<String, Integer>을 만들어서 해당 단어 나올때마다 Integer++; 해주기까지 생각이 좀 시간이 걸렸다는게 아쉽다.

또 새로 안 사실은, 아래를 통해 map을 순회할 수 있다.

for(Map.Entry<String, Integer> now : map.entrySet()) {
            q.add(new wordBook(now.getKey(), now.getValue()));
        }

풀이 링크 : https://www.acmicpc.net/source/62255771

profile
반갑습니다~! 좋은하루 보내세요 :)

0개의 댓글