BOJ 백준 5052 : 전화번호 목록
Updated:
시작하면서
이번 문제는 트라이(Trie) 문제이다. 트라이는 주로 검색 알고리즘에 쓰인다고 한다. 처음보는 개념이었고, 공부 후에 문제에 맞게 구현해서 이 문제를 해결했다.
문제 이해
문제를 읽어보자. 먼저 이 문제에서 나오는 변수는 총 3가지이다.
- t : 테스트 케이스 개수
- n : 전화번호의 수
- number : 전화번호
문제 아이디어
해당 문제의 핵심 포인트는 패턴이 겹치지 않아야 한다. 그말은 쉽게 풀자면 짧은 번호로 시작되는 다른 번호가 존재하면 일관성 있는 목록이 아닌 것이다.
문제를 푸는 방법은 다음과 같다.
- 전화번호를 받으면서 트라이(Trie)에 넣는다.
- 일관성 있는 값이 아닌 경우는 다음 2가지가 있다.
- 값을 넣던 도중에 해당 값이 이전에 존재했고, 트라이의 leaf인 경우
- 마지막 숫자를 넣었는데 해당 값이 leaf가 아니고, 해당 값의 다음 값이 존재하는 경우
해당 조건들을 기준으로 문제를 푸는데 주의할 점이 있다. 전화번호가 0으로 시작할 수도 있고, 0으로 끝날 수도 있으므로 인풋을 받을 때 int가 아닌 string을 사용해야 한다.
해결
#include <iostream>
#include <string.h>
#include <string>
#include <cmath>
using namespace std;
#define NUMBER_LENGTH (10)
/*
CLASS
*/
class Trie
{
private:
bool m_isTerminal;
bool m_isNextExist;
Trie* m_node[NUMBER_LENGTH];
public:
Trie()
{
this->m_isTerminal = false;
this->m_isNextExist = false;
memset(this->m_node, NULL, sizeof(this->m_node));
}
~Trie()
{
Clear();
}
void Clear()
{
this->m_isTerminal = false;
for (int i = 0; i < NUMBER_LENGTH; i++)
{
if (this->m_node[i])
{
delete this->m_node[i];
}
}
memset(this->m_node, NULL, sizeof(this->m_node));
}
bool Insert(const int* key, int digitCount);
Trie* Find(const int* key);
bool IsExist(const int* key);
};
bool Trie::Insert(const int* key, int digitCount)
{
if (digitCount == 0)
{
if (this->m_isNextExist == true)
return false;
this->m_isTerminal = true;
return true;
}
else
{
int index = *key;
if (this->m_node[index] == NULL)
{
this->m_node[index] = new Trie();
}
else if (this->m_node[index]->m_isTerminal == true)
{
return false;
}
this->m_isNextExist = true;
return this->m_node[index]->Insert(key + 1, --digitCount);
}
}
Trie* Trie::Find(const int* key)
{
if (*key == 0)
return this;
int index = *key;
if (this->m_node[index] == 0)
return NULL;
else
return this->m_node[index]->Find(key + 1);
}
bool Trie::IsExist(const int* key)
{
if (*key == 0 && this->m_isTerminal == true)
return true;
int index = *key;
if (this->m_node[index] == 0)
return false;
else
return this->m_node[index]->IsExist(key + 1);
}
/*
FUNCTION
*/
int GetDigitCountOfNumber(int number)
{
if (number < 0)
return -1;
int count = 0;
while (number > 0)
{
number /= 10;
count++;
}
return count;
}
int* GetNumberArrayOfNumber(int number, int digitCount)
{
if (digitCount > NUMBER_LENGTH)
return NULL;
int* arr = new int[digitCount];
int count = 0;
while (number != 0)
{
arr[digitCount - 1 - count] = number % 10;
count++;
number /= 10;
}
return arr;
}
int* GetNumberArrayOfString(string str)
{
int* arr = new int[str.length()];
for (int i = 0; i < str.length(); i++)
{
arr[i] = str[i] - '0';
}
return arr;
}
int main()
{
int t, n;
Trie* trie = new Trie();
cin >> t;
for (int i = 0; i < t; i++)
{
cin >> n;
int number = 0;
bool result = true;
for (int j = 0; j < n; j++)
{
string str;
cin >> str;
if (result == false)
continue;
int* numberArray = GetNumberArrayOfString(str);
if (trie->Insert(numberArray, str.length()) == false)
{
result = false;
}
delete[] numberArray;
}
if (result == true)
{
cout << "YES\n";
}
else
{
cout << "NO\n";
}
trie->Clear();
}
delete trie;
return 0;
}
마치며
코드에 보면 사용하지 않는 코드들도 끼어있을 것이다. Trie를 구현하면서 필요한 함수를 넣은 것도 있고, 처음에 풀 때 int를 인풋으로 받아서 사용했던 함수도 있다. (문제 이해를 잘 하자… 0이 앞 뒤로 나올줄이야…)
일상생활에서 많이 사용하는 검색에 관련된 알고리즘 개념을 공부해서 푼 문제라 상당히 유익했고, 시간 있을 때 더 고도화된 문제도 풀어보면 좋을듯하다.
Leave a comment