0~9 사이의 숫자가 공백 없이 이어진 문자열이 주어진다. 여기서 가장 많이 등장한 숫자와 그 등장 횟수를 구하면 된다. 단, 최빈값이 여러 개면 그중 더 큰 숫자를 답으로 한다.
판의 수 T ≤ 50, 한 판의 다트 수 5 ≤ N ≤ 100
각 점수는 0~9 한 자리
출력: #판번호 최빈숫자 등장횟수
값의 범위가 0~9로 딱 10개다. 크기 10짜리 카운팅 배열을 만들어 카운팅을 하려고 했다.
동점 처리는 배열을 인덱스 9부터 0까지 거꾸로 순회한다. 큰 숫자를 먼저 만나니까, 최댓값과 일치하는 순간 바로 break하면 그게 자동으로 가장 큰 최빈값이 된다.
package swea.D2_26927;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
int t = Integer.parseInt(br.readLine());
for (int i = 1; i <= t; i++) {
int n = Integer.parseInt(br.readLine());
int[] count = new int[10];
int maxNum = 0;
int maxNumCount = 0;
String s = br.readLine();
for (int j = 0; j < n; j++) {
char c = s.charAt(j);
int num = c - '0';
count[num]++;
maxNumCount = Math.max(maxNumCount, count[num]);
}
for (int j = count.length - 1; j >= 0; j--) {
if (maxNumCount == count[j]) {
maxNum = j;
break;
}
}
sb.append('#').append(i).append(" ").append(maxNum).append(" ").append(count[maxNum])
.append("\n");
}
System.out.print(sb);
}
}
append를 체이닝한 이유는 +를 쓰면 임시 StringBuilder가 생긴다는 설명을 자주 보아서 찾아보았는데, 이건 Java 8까지의 얘기다. Java 9부터 javac는 문자열 +를 invokedynamic으로 컴파일하고 StringConcatFactory가 런타임에 최적화된 메서드 핸들을 만들어준다. 임시 StringBuilder는 생기지 않는다.
그래도 중간 String 객체가 만들어졌다가 다시 sb 버퍼로 복사되는 것은 두 방식 모두 동일하다. 체이닝은 이 중간 단계 없이 버퍼에 바로 쓴다.
100만 줄 기준이면
| 방식 | 힙 할당량 | 소요 시간 |
|---|---|---|
append 안에서 + | 89 MB | 71~80 ms |
append 체이닝 | 36 MB | 67~70 ms |
할당량은 2.5배 차이가 나는데 시간은 사실상 같았다. 짧게 살다 사라지는 객체는 JIT과 GC가 워낙 저렴하게 처리하기 때문에 체감 시간으로는 잘 드러나지 않는다고 한다.
결론으로 append 체이닝 굳이 안 해도 될 듯 하다...!