티스토리 뷰
[JAVA] 백준 #4358 생태학 문제 풀이 | HashMap | TreeMap | Buffered Reader
YouJungJang 2023. 11. 16. 15:10
[1] 백준 #4358 생태학
🔒 문제 설명
생태학에서 나무의 분포도를 측정하는 것은 중요하다. 그러므로 당신은 미국 전역의 나무들이 주어졌을 때, 각 종이 전체에서 몇 %를 차지하는지 구하는 프로그램을 만들어야 한다.
⌨️ 입력
프로그램은 여러 줄로 이루어져 있으며, 한 줄에 하나의 나무 종 이름이 주어진다. 어떤 종 이름도 30글자를 넘지 않으며, 입력에는 최대 10,000개의 종이 주어지고 최대 1,000,000그루의 나무가 주어진다.
🖥️ 출력
주어진 각 종의 이름을 사전순으로 출력하고, 그 종이 차지하는 비율을 백분율로 소수점 4째자리까지 반올림해 함께 출력한다.
🗝️Solution
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
//[1] 입력을 위한 선언
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
double total = 0;
//[2] 각 나무들의 종과 나온 횟수를 저장하는 HashMap 선언
HashMap<String, Integer> trees = new HashMap<>();
//[3] 나무들 입력 받기
String input;
while ((input = br.readLine()) != null) { //나무 해쉬맵 갱신하기
total ++ ;
if(trees.containsKey(input)){ // 이미 존재하는 나무라면 count + 1
trees.put(input, trees.get(input)+1);
}
else trees.put(input,1);
}
//[4] 사전순 정렬 SortedMap
Map<String, Integer> sortedMap = new TreeMap<>(trees);
//[5] 출력
double finalTotal = total;
sortedMap.forEach((tree, count) ->
System.out.println(tree+" "+String.format("%.4f",(double)count * 100 / (double)finalTotal))
);
}
}
[2] BufferedReader VS Scanner(System.in)
- BufferedReader의 장단점
장점 | 단점 |
속도가 훨씬 빠르다. 입력된 데이터가 바로 전달되지 않고 버퍼에 채워서 한번에 전달되므로 데이터 처리 효율성이 높다. 많은 양의 데이터를 처리할 때 유리하다. |
ENTER만 경계로 인식하고 받은 데이터가 String으로 고정되기 때문에 입력값을 가공하는 작업이 필요하다. |
- BufferReader 기본 사용 방법
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 선언
String s = br.readLine();
int i = Integer.parseInt(br.readLine());
여기서 주의할 점은 BufferedReader로 읽은 데이터 값은 'String'타입으로 고정되므로 다른 타입을 받고 싶다면 꼭 형변환을 해줘야 한다는 것이다.(코드 맨 아랫줄)
- BufferedReader로 입력 받은 문장을 분리하고 싶을 때 : StringTokenizer
//1. 띄어쓰기 기준으로 문자열을 분리
StringTokenizer st = new StringTokenizer(문자열);
//2. 구분자를 기준으로 문자열을 분리
StringTokenizer st = new StringTokenizer(문자열, 구분자);
/* 3. 구분자를 기준으로 문자열을 분리할 때 구분자도 토큰으로 넣는다. (true)
* 구분자를 분리된 문자열 토큰에 포함 시키지 않는다. (false)
* (디폴트 : false)
*/
StringTokenizer st = new StringTokenizer(문자열 , 구분자 , true/false);
➕더 읽어보기
- 입력의 끝을 모를 때 : EOF(End Of File) 처리
입력의 개수가 정해지지 않고, 가변적인 상황에서는 보통 while문이나 for문을 사용해서 EOF 조건을 넣어준다. Buffered Reader나 Scanner를 사용할 때 조건문의 구성은 아래와 같이 하면 된다.
(1) BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input;
while ((input = br.readLine()) != null) {
// input에 입력받은 한 줄이 들어가 있음
}
(2)Scanner(System.in)
Scanner scan = new Scanner(System.in);
while(scan.hasNext()) {
//scan에 입력받은 값이 들어가 있음
}
➕더 읽어보기
[2] HashMap
이 문제에서 나무 이름과 입력 횟수를 각각 어디에 저장하고 어떻게 연결할 것인지 정말 고민이 많았다.
각각 Arraylist에 담아서 서로의 인덱스를 저장하는 방법, LinkedList를 사용하는 방법, 클래스를 만들어 객체 단위로 처리하는 방법 등 정말 고민이 많았는데 결국 찾아낸 것은 HashMap 이다. C++ 문제 풀이 때 써봤던 HashMap 은 Key와 Value가 짝지어져서 저장되는 자료구조이다.
Key는 하나의 HashMap에서 유일한 것이므로 결국 Key는 '나무 이름', Value는 '나무 입력 횟수'를 저장하면 되는 것이다.
//[1] HashMap 선언
HashMap<String, Integer> trees = new HashMap<>();
//[2] 나무들 입력 받기
String input;
while ((input = br.readLine()) != null) { //나무 해쉬맵 갱신하기
total ++ ;
if(trees.containsKey(input)){ // 이미 존재하는 나무라면 count + 1
trees.put(input, trees.get(input)+1);
}
else trees.put(input,1);
}
//[3] 사전순 정렬 : SrotedMap
Map<String, Integer> sortedMap = new TreeMap<>(trees);
이 때, HashMap은 개체들을 무작위로 저장하는데 우리는 출력할 때 사전 순으로 출력해야한다.
다양한 방법을 사용할 수 있겠지만 나는 TreeMap을 사용해서 사전순으로 나열했다.