렝무식

[백준 1157번] 단어 공부 (JAVA) 본문

Algorithm/Baekjoon

[백준 1157번] 단어 공부 (JAVA)

렝9 2023. 1. 12. 16:59

BOJ - [1157] 단어 공부


image

🖍 주어진 문자열에서 가장 많이 사용된 알파벳을 대문자로 출력하는 문제

(link) 1157 단어 공부


[풀이 과정]

사용한 자료구조는 배열.

배열 인덱스로 알파벳을 구분하여 각 알파벳 값이 나온 횟수를 배열에 저장하는 방법으로 풀었다. 

 

우선 크기가 27인 정수형 배열을 하나 선언한다. (이유는 나중에 설명함)

그리고 대소문자 구분 없이 카운트하므로 toUpperCase() 메소드를 사용하여 문자열을 출력 형태인 대문자로 맞춰줌.

 

이번에도 역시 문자열 charAt() 메소드로 하나씩 나누어준다. 이때 나누어진 char 데이터를 이용하여 인덱스를 결정할 것이다.

조금 더 자세히 설명하자면 char 데이터를 int 데이터와 연산하여 인덱스를 결정할건데, 이때 대문자 알파벳 A의 아스키 코드인 65를 빼주어서 인덱스 0부터 들어갈 수 있도록 할 것이다. 한마디로 인덱스 0 ~ 25의 배열 칸이 알파벳 A ~ Z의 자리가 되는 것이다. 따라서 알파벳의 아스키 코드 번호 - 65 = 배열의 인덱스가 된다. 그렇기 때문에 알파벳 개수인 26개 크기 배열을 우선 확보했다.

 

그런데 왜 배열의 크기를 27로 설정했는가?

문제에서 중복된 알파벳의 처리를 하도록 만들라고 제시했으므로, 나는 인덱스를 저장할 변수를 하나 더 선언할 것이다. (이하 index2) 그리고 이 변수의 초기값은 26으로 만든다. 배열의 26번째 데이터는 접근할 일이 없기 때문에 항상 0을 유지한다.

 

이제 문자열의 길이 만큼 반복문을 돌려 문자 아스키 코드에 맞는 배열의 데이터, 즉 카운트 값을 1씩 올려준다. 그럼 해당 알파벳이 몇 개가 사용됐는지 알 수 있다.

그리고 배열 내의 최대값을 찾아 각 변수들에 저장한다. 이때 중복된 값을 만나면 사전에 만들어둔 index2 변수에 인덱스를 저장해놓는다. (중복값을 만나지 않는다면 index2의 값은 변하지 않을 것이다)

마지막으로 최대값을 찾았는지, 아니면 중복된 개수의 알파벳이 있는지 판단한다.

최대값과 index2에 해당하는 배열 값이 같다면 이는 중복된 개수의 알파벳이기 때문에 물음표를 출력하도록 한다.

만약 같지 않으면 최대값이 있는 것이므로, 최대값으로 판명된 인덱스 숫자에 다시 65를 더해주어 char 데이터에 넣은 후 출력하면 되겠다.

pro3

난잡해서 도움이 될지는 모르겠지만 .. 시각적인 자료와 함께 예시를 가져와봤다.

(아래의 의사 코드를 파악한 후 보아야 이해됨. 근데 애니메이션이 너무 빠른 것 같다 .. 다음부터는 충분히 느리게 만들어야겠다 ㅠㅠ)

 

테스트 케이스 "zZaA"는 Z와 A가 2개로, 중복된 개수이므로 "?" 를 출력해야한다.

아스키 코드 값 연산에 맞춰 각각 배열 0번째와 25번째에 2씩 저장된다.

초기 변수는 max = 0 / index = 0 / index2 = 0 이다.

반복문 i = 0 일 때, 최대값인 2를 만나 max = 2 / index = 0 으로 변경된다.

그리고 계속 반복문을 지나 i = 25일때 중복값인 2를 만나 index2 = 25가 된다.

 

마지막 if문인 array[index] != array[index2] 에서 조건문을 만족하지 않는다.

(array[index] = 2 이고 array[index2] = 2이기 때문에)

따라서 else를 실행하게 될 것이고, 우리가 원하는 값인 "?"를 출력하게 된다.


[Pseudocode]

1. 문자열 s 입력 받기
2. 크기 27의 정수형 배열 array 선언
3. 최대값을 담을 변수 max 선언 //초기값 0
4. 최대값의 인덱스를 담을 변수 index 선언 //초기값 0
5. 중복 판별을 위한 인덱스를 담을 변수 index2 선언 // 초기값 26
6. 문자열 s를 모두 대문자로 변경
7. for i=0부터 문자열 길이까지 반복
    8. arr[s.charAt(i)-65] += 1
8. for i=0 부터 array 길이까지 반복
    10. if(array[i] == 0)
        11.continue 
    12. if(array[i] > 최대값)
        13. max = array[i]
        14. index = i
    15. if(array[i] == 최대값)
        16. index2 = i
17. if(array[index] != array[index2])  
    18. int to char
    19. char 출력
20. else
    21. "?" 출력

[Code]

import  java.util.*;
/**
* 백준 1157번
* 단어 공부
* 분류: 구현, 문자열
*/
public  class  Problem3 {
    public  static  void  main(String[] args) {
    Scanner  input = new  Scanner(System.in);
    String  s = input.next();
    int[] array = new  int[27]; // 알파벳 개수 저장 배열
    int  max = 0; // 배열 내 최대값 저장 변수
    int  index = 0; // 최대값을 가진 인덱스 저장 변수
    int  index2 = 26; // 중복값 인덱스 저장 변수
    s = s.toUpperCase();

    // 알파벳 카운트
    for(int  i=0 ; i<s.length() ; i++)
        array[s.charAt(i)-65] += 1;

    // 최대 카운트 찾기
    for(int  i=0 ; i<array.length ; i++) {
        if(array[i] == 0) // 나오지 않은 알파벳 건너뜀
        	continue;
        if(array[i] > max) { // 1. 최대값 발견 : max값 갱신
            max = array[i];
            index = i;
        }
        else  if(array[i] == max) // 2. 중복된 값 발견 : 추후 판별을 위해 인덱스 값 따로 저장
        	index2 = i;
    } 

    if(array[index] != array[index2]) { // 중복된 값이 발견되지 않았을 때
        char  c = (char)(index+65);
        System.out.println(c);
    }
    else  // 중복된 값이 발견됐을 때
        System.out.println("?");

    input.close();
    }
}

[Result]

image


(2021.07.14 풀이분)

만약 이 문제를 지금 풀어본다면 boolean 플래그 변수를 하나 만들어서 판별했을 것같다.

아니면 int 변수를 이용하여 중복값을 저장해놓고 max 변수와 크기를 비교하여 판별하는 방법도 있겠다.

아직 어떤 것이 좋고, 빠르고, 보기 좋은 코드인지 잘 모르겠지만..

Comments