✅ 문제
문제링크
🔗 https://www.acmicpc.net/problem/20920
✅ 풀이
🔹 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
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());
StringBuilder sb = new StringBuilder();
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
Map<String, Integer> map = new HashMap<>();
while (n-- > 0) {
String word = br.readLine();
if (word.length() >= m) {
map.put(word, map.getOrDefault(word, 0) + 1);
}
}
List<String> list = new ArrayList<>(map.keySet());
Collections.sort(list, (w1, w2) -> {
if (map.get(w1) == map.get(w2)) {
if (w1.length() == w2.length()) {
return w1.compareTo(w2); // 3. 사전 순으로 앞에 있는 단어를 앞에 배치
} else {
return w2.length() - w1.length(); // 2. 길이가 길수록 앞에 배치
}
} else {
return map.get(w2) - map.get(w1); // 1. 자주 나올 수록 앞에 배치
}
} );
// 우선순위 정렬 조건을 조금 더 간결하게 한 코드
/*list.sort((w1, w2) -> {
if (map.get(w1) != map.get(w2)) {
return map.get(w2) - map.get(w1);
}
if (w1.length() != w2.length()) {
return w2.length() - w1.length();
}
return w1.compareTo(w2);
});*/
// foreach문을 통해 ArrayList의 요소를 쉽게 꺼낼 수 있다.
for (String str : list) {
sb.append(str).append("\n");
}
sb.setLength(sb.length() - 1);
System.out.println(sb);
}
}
이 문제는 n
개의 영단어를 입력받아 단어장을 만드는데 중복은 제거하고 길이가 m
이상인 단어들을 다음 우선순위에 맞게 앞에 적는다.
- 1. 자주 나오는 단어일수록 앞에 배치한다.
- 2. 해당 단어의 길이가 길수록 앞에 배치한다.
- 3. 알파벳 사전 순으로 앞에 있는 단어일수록 앞에 배치한다.
자주 나오는 단어인지 확인해야하므로 HashMap
을 사용해 key
에는 단어를 저장하고 value
에는 나온 횟수를 저장하도록 하자.
StringTokenizer st
를 선언해 n
과 m
을 입력받고 저장하도록 한다.
Map<String, Integer> map = new HashMap<>();
하여 map
을 선언해주도록 한다.
while문에 조건을 n-- >0
하여 n
번 반복하도록 한다.
String word
에 단어를 입력받아 저장하고 if문에 조건을 word.length() >= m
하여 m
이상인 단어인지 확인한다.
단어의 길이가 m
이상이라면 map.put(word, map.getOrDefault(word, 0) + 1);
하여 key
에는 word
를 저장하고 value
값에는 getOrDefault()
메서드를 사용해 key
값이 있으면 해당 키의 value
값을 반환하고 key
가 없다면 value
값으로 0을 반환하도록 한다.
반환값에 + 1
해주어 세어준다.
반복이 종료되면 HashMap
은 순서가 보장되지 않으므로 List<String> list = new ArrayList<>(map.keySet());
하여 HashMap
의 key
들을 ArrayList
에 넣어도록 한다.
Collections.sort(list, (w1, w2) -> {});
하여 list
를 정렬하고 두번째 인자로 Comparator
을 람다식을 사용해 정렬 우선순위를 정해주도록 한다.
람다식에 if문에 조건을 map.get(w1) == map.get(w2)
를 주어 등장횟수가 같다면 내부에 if문에 조건을 w1.length() == w2.length()
하여 단어의 길이가 같다면 return w1.compareTo(w2);
하여 w1
이 w2
보다 사전 순으로 앞에 있다면 음수가 반환되어 정렬 시 앞쪽에 배치되도록 하고 뒤에 있다면 양수가 반환되어 정렬 시 뒤쪽에 배치되도록 한다.
단어 길이가 같지 않다면 return w2.length() - w1.length();
하여 길이가 길수록 앞에 배치되도록 한다.
w1
이 w2
보다 길다면 음수가 반환되어 정렬 시 w1
이 앞쪽에 배치될 것이고, w1
이 w2
보다 짧다면 양수가 반환되어 w1
이 뒤쪽에 배치된다.
등장횟수가 같지 않다면 map.get(w2) - map.get(w1);
하여 자주 등장하는 단어가 앞에 정렬되도록 한다.
w1
이 w2
보다 많이 등장한다면 음수가 반환되어 w1
이 정렬 시 앞쪽에 배치되게 되고, w1
이 w2
보다 적게 등장한다면 양수가 반환되어 w1
이 뒤쪽에 배치되게 된다.
이는 정렬 우선순위를 조금 확인하기 어려울 수 있으니 주석처리한 코드와 같이 if문을 우선순위가 높은 조건대로 먼저 써서 return
하게 하는 방법도 있다.
if문에 조건을 map.get(w1) != map.get(w2)
하여 등장횟수가 같지 않다면 return map.get(w2) - map.get(w1);
하여 등장횟수가 많은 것이 앞쪽에 배치되도록 한다.
이후 if문에 조건을 w1.length() != w2.length()
하여 단어의 길이가 같지 않다면 return w2.length() - w1.length();
하여 단어의 길이가 긴 단어가 앞쪽에 배치되도록 한다.
그리고 앞써 2
개의 if문이 끝나면 return w1.compareTo(w2);
하여 사전순으로 앞에 있는 단어가 앞쪽에 배치되도록 한다.
이 같은 코드는 앞선 코드 방식보다 더 코드를 확인하기 쉽고 정렬 우선순위를 파악하기 쉽다.
foreach문을 사용해 StringBuilder sb
에 정렬된 ArrayList
의 요소들을 꺼내어 넣어주도록 한다.
sb
를 출력한다.
🔹 결과
🔹 알게된 정보
HashMap
사용 시getOrDefault()
메서드를 사용하면 코드를 간결하게 할 수 있다.- 정렬 시 정렬 우선순위를 두번째 인자로
Comparator
를 사용해 람다식으로 넣어주는 방법을 기억하자. - 정렬시 정렬 우선순위를 if문을 여러개를 써서 표현하는 방식이 더 코드를 이해하기 쉽다.
- 정렬 시
return
문에w1
과w2
의 배치를 잘 생각해보고 음수를 반환하면 앞쪽에 배치되고 양수를 반환하면 뒤쪽에 배치되는 것을 기억하자.
'Problem Solving (Java) > 백준' 카테고리의 다른 글
[백준] 25501번 : 재귀의 귀재 (브론즈 Ⅱ) - Java/자바 (2) | 2025.07.04 |
---|---|
[백준] 10870번 : 피보나치 수 5 (브론즈 Ⅱ) - Java/자바 (0) | 2025.07.03 |
[백준] 2108번 : 통계학 (실버 Ⅱ) - Java/자바 (0) | 2025.07.03 |
[백준] 11050번 : 이항 계수 1 (브론즈 Ⅰ) - Java/자바 (2) | 2025.06.30 |
[백준] 10872번 : 팩토리얼 (브론즈 Ⅲ) - Java/자바 (0) | 2025.06.30 |