https://www.acmicpc.net/problem/1157
Answer1
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
String inputWord = "";
StringBuilder upperCaseWord = new StringBuilder();
StringBuilder tempWord = new StringBuilder();
StringBuilder resultChar = new StringBuilder();
char tempChar;
int count = 0;
int tempCount = 0;
try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
inputWord = br.readLine();
} catch (IOException e) {
System.err.println("ERROR : " + e.getMessage());
}
upperCaseWord.append(inputWord.toUpperCase());
while(upperCaseWord.length() > 0) {
tempCount = upperCaseWord.length();
tempChar = upperCaseWord.charAt(0);
tempWord.setLength(0);
tempWord.append(upperCaseWord.toString().replace(String.valueOf(tempChar), ""));
tempCount -= tempWord.length();
if (count == tempCount) {
resultChar.setLength(0);
resultChar.append("?");
} else if (count < tempCount) {
resultChar.setLength(0);
resultChar.append(tempChar);
count = tempCount;
}
upperCaseWord.setLength(0);
upperCaseWord.append(tempWord);
}
System.out.println(resultChar);
}
}
Code Review1
try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
inputWord = br.readLine();
} catch (IOException e) {
System.err.println("ERROR : " + e.getMessage());
}
`try-with-resources`로 try에 객체 자원을 받아서, try문이 끝나면 자동으로 자원을 반환하도록 한다.
`System.in`으로 사용자로부터 입력받은 데이터를 바이트 스트림으로 받는다.
`InputStreamReader` 클래스로 바이트 스트림을 문자 기반 스트림으로 변환한다.
`BufferedReader` 클래스로 문자 스트림을 읽는다.
upperCaseWord.append(inputWord.toUpperCase());
while(upperCaseWord.length() > 0) {
// 1
tempCount = upperCaseWord.length();
tempChar = upperCaseWord.charAt(0);
// 2
tempWord.setLength(0);
tempWord.append(upperCaseWord.toString().replace(String.valueOf(tempChar), ""));
// 3
tempCount -= tempWord.length();
if (count == tempCount) {
resultChar.setLength(0);
resultChar.append("?");
} else if (count < tempCount) {
resultChar.setLength(0);
resultChar.append(tempChar);
count = tempCount;
}
// 4
upperCaseWord.setLength(0);
upperCaseWord.append(tempWord);
}
- 1
- 입력받은 단어를 대문자로 변경한 후(ex. zZa -> ZZA), `upperCaseWord` StringBuilder 객체에 `append()` 한다.
- 예를 들어, `upperCaseWord`가 MISSISSIPI이면 이 단어의 길이가 0이 될 때까지 반복문을 돌린다.
- `tempCount`는 현재 `upperCaseWord`의 길이를, `tempChar`에는 현재 `upperCaseWord`의 첫 문자를 대입힌다.
- 2
- 현재 `tempWord.setLength(0)`로 StringBuilder 객체를 초기화하고, `upperCaseWord`의 첫 문자가 들어간 문자들을 공백으로 `replace` 처리를 한 후 `tempWord`에 대입한다. (ex. ZZA -> A)
- 3
- `tempCount`의 길이에 공백으로 `replace` 처리된 길이를 빼서 단어에 들어가 있는 첫 문자의 개수를 구한다. (ex. ZZA(3) - A(1) = 2 : Z 문자의 개수)
- `count`가 현재 `tempCount`와 같으면 결과를 ?로 한다. (가장 많이 사용된 알파벳이 여러 개 존재하는 경우이다.)
- `count`가 현재 `tempCount`보다 작으면 `count`를 현재 `tempCount`로 변경한다. (가장 많이 사용된 알파벳을 구하는 경우이다.)
- 4
- 현재 `upperCaseWord` 대신 바뀐 문자열 `tempWord`로 대체한다. (ex. ZZA -> A)
Answer2
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
String inputWord = "";
try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
inputWord = br.readLine();
} catch (IOException e) {
System.err.println("ERROR : " + e.getMessage());
}
final int ALPHABET_COUNT = 26;
final int LOWERCASE_A_DECIMAL = 97;
final int UPPERCASE_A_DECIMAL = 65;
int[] alphabetArr = new int[ALPHABET_COUNT];
for (int i = 0; i < inputWord.length(); i++) {
if ('a' <= inputWord.charAt(i) && inputWord.charAt(i) <= 'z') {
alphabetArr[inputWord.charAt(i) - LOWERCASE_A_DECIMAL]++;
} else {
alphabetArr[inputWord.charAt(i) - UPPERCASE_A_DECIMAL]++;
}
}
int max = -1;
char resultChar = '?';
for (int i = 0; i < ALPHABET_COUNT; i++) {
if (alphabetArr[i] > max) {
max = alphabetArr[i];
resultChar = (char) (i + UPPERCASE_A_DECIMAL);
} else if (alphabetArr[i] == max) {
resultChar = '?';
}
}
System.out.println(resultChar);
}
}
Code Review2
중복 코드는 Code Review1 참고
final int ALPHABET_COUNT = 26;
final int LOWERCASE_A_DECIMAL = 97;
final int UPPERCASE_A_DECIMAL = 65;
int[] alphabetArr = new int[ALPHABET_COUNT];
알파벳의 개수는 대소문자를 구별하지 않고 A부터 Z까지 총 26개이다. 따라서 `ALPHABET_COUNT`의 값은 26.
소문자의 범위는 십진수로 97~122이다. 따라서 `LOWERCASE_A_DECIMAL`의 값은 97.
대문자의 범위는 십진수로 65~90이다. 따라서 `UPPERCASE_A_DECIMAL`의 값은 65.
알파벳 문자의 개수만큼 배열을 생성한다.
for (int i = 0; i < inputWord.length(); i++) {
if ('a' <= inputWord.charAt(i) && inputWord.charAt(i) <= 'z') {
alphabetArr[inputWord.charAt(i) - LOWERCASE_A_DECIMAL]++;
} else {
alphabetArr[inputWord.charAt(i) - UPPERCASE_A_DECIMAL]++;
}
}
이 코드에서 단어에서 어떤 문자가 몇 번 나왔는지 검사한다.
예를 들어, 'B' 문자를 입력받았을 때 두 번째 원소인 index 값 1을 가져와야 하기 때문에 66 - 65 = 1을 해주면 된다. (그래서 위의 변수를 97과 65로 생성해 뒀다.)
그리고 'B' 문자가 단어에서 2개라면 해당 문자가 들어가 있는 만큼 해당 index 자리의 숫자 늘려가서 [0, 2, 0, ...] 이런 식으로 만들어진다.
'a', 'z' 대신 단어의 십진수를 두어도 되고,
`inputWord.charAt(i)`에 단어의 십진수 대신 'a', 'z'같은 문자로 빼도 된다.
int max = -1;
char resultChar = '?';
for (int i = 0; i < ALPHABET_COUNT; i++) {
if (alphabetArr[i] > max) {
max = alphabetArr[i];
resultChar = (char) (i + UPPERCASE_A_DECIMAL);
} else if (alphabetArr[i] == max) {
resultChar = '?';
}
}
최댓값을 저장할 `max`라는 변수를 최솟값이 0이라 -1로 초기화하여 생성한다.
`alphabetArr` 배열을 반복문을 돌려서 해당 index의 원소값이 `max`보다 클 경우 해당 원소값을 `max`로, `resultChar`의 문자를 해당 index에 해당하는 문자로 변경한다. (이때 대문자를 반환해야 하므로 해당 index에 `UPPERCASE_A_DECIMAL` 65를 더해준다.)
만약 해당 index의 원소값이 `max` 값이랑 같을 경우 최대 개수의 문자가 2개 이상이라는 의미이므로 `resultChar`의 문자를 '?'로 변경한다.
Result
Answer1으로 풀었을 때는 그냥 문제대로만 풀었는데 코드도 복잡해 보이고 성능도 좋지 않았다.
다른 방법으로 풀 수는 없을까 생각하다가 찾아보니까 알파벳 10진수를 사용하여 푸는 사람이 많아서 참고하여 다시 풀어보니 코드도 더 읽기 편하고 성능도 좋았다.
이번 기회에 a-z, A-Z의 십진수 정도는 알고 갈 수 있어서 좋았다. (소문자 a는 97, 대문자 A는 65)