이에 해당하는 문제는 11654번, 11720번, 10809번, 2675번, 1157번, 1152번, 2908번, 5622번, 2941번, 1316번으로 총 10문제다.
이 글에서는, 내가 다소 지저분하게 푼 1157번과 10문제중에 가장 괜찮은 문제였던 1316번에 대해 다루고자 한다.
1157번은 대소문자가 혼합된 단어가 주어지면, 그 단어 중 대소문자에 상관없이 가장 많이 쓰인 문자를 대문자로 출력하라는 문제인데, 풀 땐 그냥 끄적이다가 푼 것 같은데 역시나 다른 사람들의 풀이를 보고 현타가 왔다.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class Main {
public static void main(String args[])
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String str;
int al[] = new int[26];
try{
str = br.readLine().toLowerCase();
for(int i=0;i<str.length();i++)
al[str.charAt(i)-'a']++;
int max=al[0], max_index = 0;
for(int i=1;i<26;i++) {
if(max<al[i]) {
max = al[i];
max_index=i;
}
}
for(int i=1;i<26;i++) {
if(max==al[i]&&max_index!=i) {
max_index=-1; break;
}
}
if(max_index!=-1)
bw.write(""+(char)(max_index+65));
else
bw.write("?");
bw.flush(); br.close(); bw.close();
}catch (Exception e){
}
}
}
나는 메인함수에서 시간복잡도가 문자열크기 + 26 + 26인데, 문자열크기 + 26만으로도 문제를 푸신 분이 계셨다. 나는 26번의 횟수를 낭비한 것.... 그 사람의 풀이를 내내 보고도 이해가 되지 않은 걸로 보아 나는 아직 절대 그 횟수로는 풀 수 없는 머리인가보다 싶어 포기했다.
대강 기억나는 부분은, '같은 크기의 경우가 존재한다' 는 의미의 변수를 하나 만든 뒤 26번 안에 나와 똑같이 맥스값을 찾다가 맥스값이 찾은 값과 같은 경우는 이 변수를 true, 맥스값을 갱신하는 경우는 false를 대입해 나중에 이 변수의 값에 따라 물음표를 출력할지 맥스를 출력할지 구분지으셨다. 아마 '맥스 값이 새로 갱신되기 전 까지 같은 횟수의 문자가 있는지 여부'에 대한 값을 갖는 변수였고, 그래서 맥스값이 갱신될 때에는 false를 통해 새로 갱신된 최댓값이 있으니 맥스값이 겹치는 일은 없다고 판단하고, true 라면 맥스값이 더이상 갱신되지 않았으므로 맥스값이 겹친다고 판단시키게끔 하신 것 같다.
이 문제는 좀 재밌는 문제였다. 문자열 안의 각 문자들이 모두 연속되는 구성 방식이라면(한번씩도 포함) 이 문자는 그룹단어라는 용어가 나왔다. aabbcc는 그룹단어인데 aabbcca는 a가 멀어지게 되었으므로 그룹단어가 아닌 것.
import java.util.Scanner;
public class Main {
public static void main(String args[])
{
Scanner scan = new Scanner(System.in);
String str;
int count=0;
int T = scan.nextInt();
scan.nextLine(); // nextInt()는 개행문자를 버리고 받아서 개행문자가 뒤에서 읽히게 됌. 참고로 Scanner도 버퍼를 사용함.
for(int i=0; i<T; i++) {
str = scan.nextLine();
if(is_group(str))
count++;
}
System.out.println(count);
}
public static boolean is_group(String str) {
int alpha[] = new int[26];
char last_c = str.charAt(0);
alpha[str.charAt(0)-'a']++;
for(int i =1; i<str.length(); i++)
{
if(last_c==str.charAt(i))
;
else
{
last_c = str.charAt(i);
if(alpha[last_c-'a']>0)
return false;
else
alpha[last_c-'a']++;
}
}
return true;
}
}
주의할 점은 주석에 적어놓았다. 숫자를 입력받은 뒤 문자를 입력받아야 할 때 nexInt()와 nextLine()을 붙여 쓰게 되면 원하지 않는 문제가 발생한다. 7을 입력하고 hello를 입력하려고 마음먹고 7을 입력하고 엔터를 땅 치는 순간 nextInt()에는 7이 들어가게 되지만, nextInt()는 개행문자를 버리고 가져오기 때문에 남아있던 엔터(\n) 문자가 바로 다음 nextLine()에서 읽어들여지는 것이다. (버퍼의 개념에 대해 굳이 생각하지 않아도 그냥 입력한 게 7\n 인데 nextInt()에서는 7가져가니 바로 뒤에서 실행되는 nextLine()가 개행문자를 읽게되는게 당연할 것이다) 따라서 위와 같이 엔터값을 버려주기 위해 nextLine()을 하나 넣어놔 줘야 한다.