문제
[BOJ[C++] 백준 1157번: 단어공부
문제는 https://www.acmicpc.net/problem/1157를 클릭해서 볼 수 있다.
풀이
아스키 코드를 이용하여 문자의 개수를 세는 문제였다. character_count[26] 배열을 만들어 단어에서 'A'부터 'Z'까지 각 문자가 몇 번 나왔는 지 개수를 저장했다. 문자는 index가 0이면 'A', index가 25이면 'Z' 이런 식으로 구분했다.
먼저 소문자와 대문자의 구분을 없앴다. 단어의 길이만큼 반복문을 돌면서 소문자인 경우 아스키 코드값 차이만큼 빼 대문자로 바꾸어 주었다. (소문자는 대문자보다 아스키 코드값이 각각 32 만큼 크다.) 그런 다음 character_count 배열에서 개수를 1씩 더해줬다.
다음은 가장 많이 사용된 문자를 찾았다. character_count를 돌면서 max_count보다 크면 max_count 값을 현재 개수로 갱신해주고, max_used_character에 현재 문자를 저장해줬다.
가장 많이 사용된 문자의 개수는 max_count와 같은 개수를 가지는 다른 문자가 있는 지 확인해서 구했다. 다른 문자가 있으면 ? 없으면 max_used_character를 출력해 답안을 완성했다.
공부
첫 제출에서 시간 초과가 나왔다. 문제를 풀 때 시간 제한이 2초이고 주어진 단어의 길이가 1,000,000을 넘지 않기 때문에 시간이 충분하다고 생각했다. 시간 초과가 날 만한 코드를 찾다가 for문 코드를 살펴보게 되었다. 예상대로 시간 초과의 범인은 get_character_count() 함수의 for문이었다.
for문 안 조건식에 i < strlen(word) 를 넣으면 조건을 확인할 때 마다 strlen 함수가 실행된다. strlen는 문자열에서 NULL 이 들어올 때까지 문자열을 하나씩 읽는다. 문자열의 길이가 n일 때 for문의 시간 복잡도는 O(n^2) 가 된다. 따라서 시간 초과를 피하기 위해 for문 밖에서 length_of_word = strlen(word) 처럼 한 번만 실행되도록 바꿔주거나 word[i] ! = '\0' 으로 NULL이 들어오기 전까지로 조건식을 바꿔주어야 한다.
호호님의 코드를 보면서 가장 많이 사용된 문자의 개수를 더 쉽게 구하는 방법에 대해 알게 됐다. 필자는 가장 많이 사용된 문자를 구한 뒤 다시 반복문을 돌면서 개수를 구했다. 호호님은 가장 많이 사용된 문자를 구할 때 max_count랑 현재 개수가 같으면 지금까지 구한 max_used_character는 적어도 2개 이상이라는 뜻이므로 -1로 표시해주셨다. 이렇게 하면 max_count는 그대로 살릴 수 있으면서 가장 많이 사용된 문자가 몇 개인지 까지 한번에 구할 수 있다.
// 호호님 코드 else if (current_count == max_count && current_character != 0) // 가장 많이 사용된 알파벳이 2개 이상이라는 뜻이다. max_used_character = -1; // 필자의 코드 int check_number_of_most_used_character() { for (i = 0; i < 26; i++) { if (character_count[i] == max_count && i + 65 != max_used_character) return 1; // 2개 이상 존재 } return 0; // 한 개만 존재 }
코드
정답 코드 1
#include <stdio.h> #include <string.h> char word[1000001] = ""; // 알파벳 대소문자로 이루어진 단어 int character_count[26] = {0}; // 사용된 알파벳의 개수 int i = 0; int current_character; int max_used_character, max_count; void get_character_count(); void find_most_used_character(); int check_number_of_most_used_character(); int main() { scanf("%s", word); get_character_count(); find_most_used_character(); if (check_number_of_most_used_character() == 0) printf("%c\n", max_used_character); else printf("?\n"); return 0; } void get_character_count() { for (i = 0; word[i] != '\0'; i++) { current_character = word[i]; // 소문자일 경우 대문자로 변환한다. if (current_character >= 'a') current_character -= 32; character_count[current_character - 65]++; } } void find_most_used_character() { for (i = 0; i < 26; i++) { int current_count = character_count[i]; if (current_count > max_count) { max_count = current_count; max_used_character = i + 65; } else if (current_count == max_count) max_used_character = -1; } } int check_number_of_most_used_character() { for (i =0; i < 26; i++) { if (character_count[i] == max_count && i + 65 != max_used_character) return 1; // 2개 이상 존재 } return 0; // 한 개만 존재 }
정답 코드 2
#include <stdio.h> #include <string.h> char word[1000001] = ""; // 알파벳 대소문자로 이루어진 단어 int character_count[26] = {0}; // 사용된 알파벳의 개수 int i = 0; int current_character; int max_used_character, max_count; void get_character_count(); void find_most_used_character(); int main() { scanf("%s", word); get_character_count(); find_most_used_character(); if (max_used_character != -1) printf("%c\n", max_used_character); else printf("?\n"); return 0; } void get_character_count() { for (i = 0; word[i] != '\0'; i++) { current_character = word[i]; // 소문자일 경우 대문자로 변환한다. if (current_character >= 'a') current_character -= 32; character_count[current_character - 65]++; } } void find_most_used_character() { for (i = 0; i < 26; i++) { int current_count = character_count[i]; if (current_count > max_count) { max_count = current_count; max_used_character = i + 65; } else if (current_count == max_count && current_character != 0) // 가장 많이 사용된 알파벳이 2개 이상이라는 뜻이다. max_used_character = -1; } }
채점 결과

'[알고리즘]' 카테고리의 다른 글
C++ 백준 22351번: 수학은 체육과목 입니다 3 (4) | 2022.06.17 |
---|---|
백준 6604번: Matrix Chain Multiplication (0) | 2022.04.27 |
백준 1431번: 시리얼 번호 (0) | 2022.04.27 |
백준 1920번: 수 찾기 (0) | 2022.04.27 |
백준 10026번: 적록색약 (6) | 2022.04.24 |