https://www.acmicpc.net/problem/20920
20920번: 영단어 암기는 괴로워
첫째 줄에는 영어 지문에 나오는 단어의 개수 $N$과 외울 단어의 길이 기준이 되는 $M$이 공백으로 구분되어 주어진다. ($1 \leq N \leq 100\,000$, $1 \leq M \leq 10$) 둘째 줄부터 $N+1$번째 줄까지 외울 단
www.acmicpc.net
package BOJ20920;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import java.util.Map.Entry;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken()); // 단어 개수
int M = Integer.parseInt(st.nextToken()); // 단어 길이 기준
Map<String, Integer> word = new HashMap<>();
int index = 0;
while(index < N) {
st = new StringTokenizer(br.readLine());
String s = st.nextToken();
if(s.length() >= M) {
word.put(s, word.getOrDefault(s, 0) + 1); // key : 단어, value : 몇 번 나오
}
index++;
}
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(word.entrySet());
Collections.sort(entryList, (o1, o2) -> {
if(o2.getValue() - o1.getValue() != 0) {
return o2.getValue() - o1.getValue(); // value 크면(자주 나오는 단어) 앞으로
} else if (o2.getKey().length() - o1.getKey().length() != 0) {
return o2.getKey().length() - o1.getKey().length(); // key 길이(=단어 길이) 길수록 앞으로
} else {
return o1.getKey().compareTo(o2.getKey()); // 알파벳 순으로
}
});
// for(int i = 0; i<entryList.size(); i++) {
// System.out.println(entryList.get(i).getKey());
// }
StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i<entryList.size(); i++) {
stringBuilder.append(entryList.get(i).getKey()).append("\n");
}
System.out.println(stringBuilder.toString());
}
}
통과하고나서 굉장히 얼떨떨했다
정렬하는 방법은 맞는거 같은데 시간초과가 나와서 이것저것 조금씩 바꿔보고 반복했다 근데도 계속 시간초과만 떠서 어떤걸 더 해봐야할지 고민이 많았다 마지막으로 map에서 key만 가져와서 배열로 만들고 비교할까? 하는 생각이 들어서 고쳐보려다가 잠시 환기 차 풀었던 문제에서 썼던 BufferedReader를 써서 가볍게 고쳐본건데,,, 통과한거다😮😮😮😮😮😮😮😮
약간 황당할 정도였다 그렇게 고민하며 고치고고칠때는 계속 시간초과가 나더니,,,
앞으로 백준 문제 입력은 무조건 BufferedReader 를 써야겠다 아주 간단한 입력 제외하고!
시간초과로 인해 헤맸던 기록은 뒤에 남기고 우선 답을 냈던 과정을 쓰자면
.
.
int index = 0;
while(index < N) {
st = new StringTokenizer(br.readLine());
String s = st.nextToken();
if(s.length() >= M) {
word.put(s, word.getOrDefault(s, 0) + 1); // key : 단어, value : 몇 번 나오
}
index++;
}
한줄씩 문자를 입력받고 길이가 M 이상일떄만 HashMap에 넣고 나오는 횟수를 더해줬다
이는 자주 나오는 단어가 우선순위 기준에 들어가기 때문에 꼭 필요한 과정이다
key는 단어고 value는 그 단어가 나온 횟수
이제는 우선순위 조건엔 맞게 정렬해주면 되는데
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(word.entrySet());
Collections.sort(entryList, (o1, o2) -> {
if(o2.getValue() - o1.getValue() != 0) {
return o2.getValue() - o1.getValue(); // value 크면(자주 나오는 단어) 앞으로
먼저, 정렬을 해주기 위해 HashMap을 ArrayList로 바꿔주었다
자주 나오는 단어가 앞으로 와야하기때문에 value 기준으로 내림차순 정렬!
else if (o2.getKey().length() - o1.getKey().length() != 0) {
return o2.getKey().length() - o1.getKey().length(); // key 길이(=단어 길이) 길수록 앞으로
}
다음 우선순위 조건으로
단어의 길이가 길수록 앞으로 오기 때문에 key의 길이 기준으로 내림차순 정렬!
else {
return o1.getKey().compareTo(o2.getKey()); // 알파벳 순으로
}
다음 우선순위 조건으로 알파벳 사전순으로 정렬!
이렇게까지 하면 정렬이 완료되고 출력해주면 끝!!!!!!
시간초과 났던 기록✨
아래가 가장 처음 제출했던 코드이다
import java.util.*;
import java.util.Map.Entry;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 단어 개수
int M = sc.nextInt(); // 단어 길이 기준
Map<String, Integer> word = new HashMap<>();
int index = 0;
while(index < N) {
String s = sc.next();
if(s.length() >= M) {
word.put(s, word.getOrDefault(s, 0) + 1); // key : 단어, value : 몇 번 나오
}
index++;
}
List<Map.Entry<String, Integer>> entryList = new LinkedList<Map.Entry<String,Integer>>(word.entrySet());
entryList.sort(new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if(o2.getValue() - o1.getValue() != 0) {
return o2.getValue() - o1.getValue(); // value 크면(자주 나오는 단어) 앞으로
} else if (o2.getKey().length() - o1.getKey().length() != 0) {
return o2.getKey().length() - o1.getKey().length(); // key 길이(=단어 길이) 길수록 앞으로
} else {
return o1.getKey().compareTo(o2.getKey()); // 알파벳 순으로
}
}
});
//System.out.println(entryList);
for(int i = 0; i<entryList.size(); i++) {
System.out.println(entryList.get(i).getKey());
}
}
}
1. LinkedList 보다 ArrayList가 좀 더 빠르게 확인할 수 있다고 하여 변경
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(word.entrySet());
2. System.out.println 보다 출력 속도가 빠른 StringBilder 이용하여 변경
StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i<entryList.size(); i++) {
stringBuilder.append(entryList.get(i).getKey()).append("\n");
}
System.out.println(stringBuilder.toString());
3. 람다식으로 변경
Collections.sort(entryList, (o1, o2) -> {
이외에도 Comparator 를 따로 빼서 정의하고 sort 에 넣어주기 등 시간초과를 잡기 위한 정말 많은 시도를 했었다
요즘 코테를 풀면서 느끼는건 효율성 있게, 시간초과 안나게 작성하는게 정말 어렵다는거다 더 좋은 방향으로 생각할 수 있도록 더 많은 문제를 풀고 더 노력해야겠다
'코딩테스트-알고리즘 > 백준 BOJ' 카테고리의 다른 글
[백준 BOJ/Silver IV] 11399번 : ATM (1) | 2024.01.27 |
---|---|
[백준 BOJ/Silver III] 9095번 : 1, 2, 3 더하기 (1) | 2024.01.27 |
[백준 BOJ/Silver IV] 11047번 : 동전 0 (1) | 2024.01.25 |
[백준 BOJ/Silver V] 2563번 : 색종이 (0) | 2024.01.23 |
[백준 BOJ/Gold IV] 1987번 : 알파벳 (0) | 2024.01.21 |