[Algorithm/Java] 백준 2108번 - 통계학
https://www.acmicpc.net/problem/2108
🔍 문제 풀이
Collections.max(map.values())
Collections.max(map.values())
는 컬렉션(이 문제에서는 map의 value들 중) 에서 가장 큰 값을 찾는 메서드이다.
map.values()
- → Map에 저장된 모든 값(value) 들을 가져온다.
- e.g.,
{1=2, 2=3, 3=3}
이면map.values()
는 `[2, 3, 3].
Collections.max(...)
- → 주어진 값들 중 최댓값을 리턴한다.
map이 아래와 같다고 할 때:
{10=2, 20=3, 30=1, 40=3}
→ 각 숫자(10, 20, 30, 40)가 나온 횟수(빈도)를 저장한 것
→ 가장 많이 나온 횟수(최빈값의 빈도수)는 3
이를 얻기 위해 사용하는 게 Collections.max(map.values())
그럼 최빈 값이 여러 개일 경우 어떻게 하지?
여러 개일 수 있으니 리스트에 담고 정렬 후 조건 처리한다.
int maxFreq = Collections.max(map.values());
List<Integer> modeList = new ArrayList<>();
for (int key : map.keySet()) {
if (map.get(key) == maxFreq) {
modeList.add(key);
}
}
Collections.sort(modeList); // 오름차순 정렬
int mode = modeList.size() >= 2 ? modeList.get(1) : modeList.get(0); // 두 번째로 작은 값
entrySet()과 Map.Entry
코드 | 의미 |
---|---|
Map.Entry<K, V> |
Map의 key-value 한 쌍을 표현하는 객체 |
map.entrySet() |
Map 안의 모든 entry(key, value)를 Set으로 반환 |
entry.getKey() |
해당 쌍의 key |
entry.getValue() |
해당 쌍의 value |
entrySet()
entrySet()
은Map
에 저장된(key, value)
쌍 전체를Set
형태로 반환한다.- 즉, Map을 반복문으로 순회할 때 사용하는 대표적인 방식이다.
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
int key = entry.getKey();
int value = entry.getValue();
// key: 숫자, value: 등장 횟수
}
왜 사용할까?
최빈값을 구하기 위해선 모든 (숫자, 횟수) 쌍을 하나씩 검사해야 한다.
이때 entrySet()
을 사용하면 key와 value를 동시에 쉽게 꺼낼 수 있다.
// value가 maxFreq인 key들만 리스트에 모으기
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() == maxFreq) {
modes.add(entry.getKey());
}
}
💻 전체 코드
import com.sun.jdi.Value;
import java.io.*;
import java.security.Key;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int[] arr = new int[n];
double sum = 0;
Map<Integer, Integer> map = new HashMap<>();
for(int i=0; i<n; i++){
int x = Integer.parseInt(br.readLine());
arr[i] = x;
sum += x;
map.put(x, map.getOrDefault(x , 0) + 1);
}
Arrays.sort(arr);
// 산술 평균
System.out.println(Math.round(sum/n));
// 중앙값
System.out.println(arr[n/2]);
// 최빈값
int frequencyNum = Collections.max(map.values());
List<Integer> frequencyList = new ArrayList<>();
// 방법1) map.entrySet()
for(Map.Entry<Integer, Integer> entry: map.entrySet()){
if(entry.getValue() == frequencyNum){
frequencyList.add(entry.getKey());
}
}
s
// 방법2) map.keySet()
for (int key : map.keySet()) {
if (map.get(key) == frequencyNum) {
frequencyList.add(key);
}
}
Collections.sort(frequencyList);
if(frequencyList.size() > 1){
System.out.println(frequencyList.get(1));
}else{
System.out.println(frequencyList.get(0));
}
// 범위
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i=0; i<n; i++){
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
System.out.println(max - min);
}
}
💭 배운 점
- 최빈값을 구할 때 단순히 Map에서 찾는 것만으로는 부족하고,
최빈값 후보들을 List에 모아 정렬한 후 두 번째로 작은 값을 출력해야 한다. Map.Entry
와entrySet()
을 통해 (key, value) 쌍을 순회할 수 있다.Math.round()
를 쓰면 산술평균을 정확하게 반올림할 수 있다.
댓글남기기