본문 바로가기
study/CodingTest

백준 1316 그룹 단어 체커 (Java)

by 고기만두(개발자) 2021. 11. 20. 16:03
728x90
반응형

문제

그룹 단어란 단어에 존재하는 모든 문자에 대해서, 각 문자가 연속해서 나타나는 경우만을 말한다.

예를 들면, ccazzzzbb는 c, a, z, b가 모두 연속해서 나타나고,

kin도 k, i, n이 연속해서 나타나기 때문에 그룹 단어이지만,

aabbbccb는 b가 떨어져서 나타나기 때문에 그룹 단어가 아니다.

 

단어 N개를 입력으로 받아 그룹 단어의 개수를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 단어의 개수 N이 들어온다.

N은 100보다 작거나 같은 자연수이다.

둘째 줄부터 N개의 줄에 단어가 들어온다.

단어는 알파벳 소문자로만 되어있고 중복되지 않으며, 길이는 최대 100이다.

출력

첫째 줄에 그룹 단어의 개수를 출력한다.


처음 풀었을 때 틀린 답이라고 나와서... 왤까 하고 IDE에 올려 디버그 하나하나 태워보며 수정하였다.

import java.io.*;

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 answer = 0;
        
        for(int i = 0; i < n ; i++){    //단어 갯수만큼 반복
            String str = br.readLine();    //단어를 입력받음
            if(checker(str)){    //그룹단어 함수 입력해서 true이면
               answer++;    //갯수를 하나씩 까준다
            } 
        }
        System.out.println(answer);
    }
    
    //체크 함수 : T/F판별만 하므로 boolean 타입
    public static boolean checker(String word) throws IOException{
        boolean check[] = new boolean[26];    //a부터 z까지 담을 배열 26자리
        for (int j = 1; j < word.length(); j++){    //마지막까지 보자
            if(word.charAt(j-1) != word.charAt(j) ){    //앞뒷글자가 다른 경우
                if(check[word.charAt(j)-'a'] == true){    //해당 번지가 이미 나온 경우
                    return false;    //false 찍고 끝
                } else{
                    //앞뒷글자가 다른데 지금까지 나오지 않은 새로운 글자가 나온 경우
                    check[word.charAt(j-1)-'a'] = true;    //true 로 변경    
                }
                
            } else {
                continue;
            }
        }
        return true;
    }
        
}

main에서 단어 갯수를 먼저 입력받는다.

그리고 단어 갯수만큼 반복하여, 단어를 입력받고 해당 단어를 checker 함수에 집어넣어

함수가 내뱉는 결과값이 true이면 answer를 하나씩 더해주는 방식을 사용하였다.

 

String타입의 단어 인풋을 입력받는 boolean 타입 함수 checker를 하나 만들었다.

이때 static 타입을 사용하지 않으면 컴파일 에러가 떴다.

 

boolean 타입의 26자리 배열(알파벳 소문자만 입력이 들어오므로 소문자 갯수 26개)을 하나 만들었고,

 

0번지와 1번지, 1번지와 2번지 ... word.length()-1번지와 word.length()번지 까지의 비교를 해야하므로

1부터 단어 길이 word.length()가 되기 전까지 반복을 돌린다.

 

j-1번지와 j번지를 비교하는데 두 글자가 같으면 그냥 같은 거니까 더 비교할 필요 없이 다음으로 넘기면 된다.

그래서 continue 해버리면 되는데, 앞뒷글자가 다를 때 문제가 된다.

 

새로운 다른 글자가 나온 경우라면, "j-1 번지"의 값을 true로 바꿔주면 된다.

 

뒷번지가 앞에서 이미 나온적 있는 글자라면, true 일 것이다.

이럴때는 return false 찍고 그룹단어 아니라고 체크하고 반복을 멈춰준다.

 

(아, 왜 -'a'냐고? 아스키 코드 변환때문에 'a'를 해줘야 한다. 

word.charAt(j)를 하면 j번지 글자의 아스키 코드값이 나오기 때문이다.)

 

실제로 j-1번지 true 부분을 고려하지 못해 오답이 나와 디버그해본 결과 반례를 찾을 수 있었다.

j번지 true로 체크하면 aba 같은 문자열에서

a != b인데 b가 그동안 나온적 없으므로 b에 해당하는 "1번지"에 true를 체크했다.

이러면 그다음 b != a 인데 a가 이미 나왔는데도 불구하고 a 가 이제서야 true 체크되고 함수가 끝나면서 

그룹단어가 아닌데도 그룹단어로 판별하는 오류를 저지른다.

a != b 이면 a에 true 체크 ->그다음 b!= a 인데 a가 이미 true네? 이미 나온적이 있었네-> 그룹함수 아님 빠잉.

728x90
반응형

댓글