백준

백준[20920]번 : 영단어 암기는 괴로워 ( JAVA )

하루우울루 2023. 4. 8. 19:55

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


Code

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
import java.util.stream.Collectors;

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());
		
		HashMap<String,Integer> map = new HashMap<>();

		int n = Integer.parseInt(st.nextToken());
		int m = Integer.parseInt(st.nextToken());
		
		String[] arr = new String[n];
		
		for(int i=0;i<n;i++) {
			arr[i] = br.readLine();
		}
		
		for(int i=0;i<n;i++) {
			if(arr[i].length() >= m) {
				if(map.containsKey(arr[i])) {
					map.put(arr[i], map.get(arr[i])+1);
				}
				else {
					map.put(arr[i], 1);
				}
			}
		}
		
		List<String> words = map.keySet().stream().collect(Collectors.toList());
		
		words.sort((o1,o2)->{
			int c1 = map.get(o1);
			int c2 = map.get(o2);
			
			if(c1==c2) {
				if(o1.length() == o2.length()) {
					return o1.compareTo(o2);
				}
				return o2.length()-o1.length();
			}
			return c2-c1;
		});
		
		StringBuilder sb = new StringBuilder();
		for(int i=0;i<words.size();i++) {
			sb.append(words.get(i)).append("\n");
		}
		
		System.out.println(sb);

		br.close();
	}
}

map을 사용해서 문자열의 빈도를 저장하는 것까진 했는데 그 뒤로 어떻게 해야 할지 생각이 잘 안 났다.

 

인터넷을 찾아보고 풀었는데 모르는 부분이 많았다.

 

List <String> words = map.keySet(). stream(). collect(Collectors.toList());

먼저, 이 부분은 map이라는 맵(Map) 객체에서 키(Key)들을 추출하여 스트림(Stream)으로 변환한 뒤, 해당 스트림을 Collectors.toList()를 사용하여 리스트(List) 객체로 수집(collect)하는 역할을 한다.

 

어려운 말이라 이해가 잘 안 되는데 List에 map의 key값들을 추출해서 저장해 준다고 생각하고 있다.

 

words.sort((o1, o2)->{
int c1 = map.get(o1);
int c2 = map.get(o2);

if(c1==c2) {
if(o1.length() == o2.length()) {
return o1.compareTo(o2);
}
return o2.length()-o1.length();
}
return c2-c1;
});

다음은 이 부분인데, 람다식이 쓰였다.람다식을 사용할 때 o1,o2 이 부분이 선언 없이 사용된 것에 의문이 있었는데 람다식에서는 콘텍스트에서 암묵적으로 타입 추론을 통해 자동으로 추론되는 매개변수로 사용된다고 한다.

 

c1과 c2는 key값의 빈도수를 의미하고 값이 같을 때 길이를 비교하게 된다.반환값에서 compareTo가 사용되었는데 두 객체를 비교해서 정수값을 반환하게 한다.0이라면 두 값이 같다는 의미이고 음수라면 앞의 값이 작으니 정렬순서상 앞에 위치한다는 의미이다.반대로 양수라면 두 번째 값이 작으니 정렬순서상 뒤에 위치한다는 의미이다.

 

그렇게 저장된 words를 StringBuilder에 넣어 출력한다.