문제 풀이

 

주어진 문자열 집합 S에서 입력되는 M개의 문자열이 같은 게 몇 개인지를 찾는 문제다.

단순히 생각해보면 전체 집합 S에서 전체 M개의 문자열을 2중 탐색으로 반복해서 문자열 비교까지 하게 된다면

시간 복잡도가 O(10,000 x 10,000 x 500) = 2초를 훌쩍 넘는다.

 

여기서 줄일 수 있는 방법은 문자열 탐색 속도를 줄이는 것이다.

균형 이진 탐색 트리를 사용하는 set이나 map을 이용하게 되면 O(logN) 만에 탐색 속도를 줄일 수 있다.

 

소스 코드

 

#include <iostream>
#include <map>
#include <string>
#include <vector>

using namespace std;

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    
    int N, M;
    cin >> N >> M;
    map<string, bool> m;
    for(int i = 0; i < N; i++)
    {
        string str;
        cin >> str;
        m[str] = true;
    }
    
    int cnt = 0;
    for(int i = 0; i < M; i++)
    {
        string str;
        cin >> str;
        if(m[str] == true)
        {
            cnt++;
        }
    }
    
    cout << cnt << endl;
    return 0;
}
트라이 이용

 

신기하게도 이 문제는 트라이 자료구조를 이용해서 풀 수 있다.

다만 시간 복잡도가 map은 O(문자열의 개수 10000 x 탐색 시간(log10000))이지만

트라이는 O(문자열의 개수 10000 x 문자열의 길이 500)이므로 여기서는 트라이가 더 느리다.

 

트라이가 항상 빠르다고 생각하면 큰 오산이 되는 문제다.

 

트라이에 문자열 집합 S를 넣어서 완성시키고, 쿼리마다 find 함수를 통해서 등록되어 있으면 카운팅 해주면 된다.

소스 코드(트라이)

 

#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct Trie
{
    Trie* ch[26];
    bool end;
    
    Trie() : end(false)
    {
        for(int i = 0; i < 26; i++)
            ch[i] = nullptr;
    }
    
    ~Trie()
    {
        for(int i = 0; i < 26; i++)
            if(ch[i]) delete ch[i];
    }
    
    void insert(const char* str)
    {
        if(!*str)
        {
            end = true;
            return;
        }
        
        int cur = *str - 'a';
        if(!ch[cur]) ch[cur] = new Trie();
        ch[cur]->insert(str + 1);
    }
    
    bool find(const char* str)
    {
        if(!*str)
        {
            if(end) return true;
            return false;
        }
        int cur = *str - 'a';
        if(!ch[cur]) return false;
        return ch[cur]->find(str + 1);
    }
};

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    
    int n, m;
    cin >> n >> m;
    Trie* root = new Trie();
    string str;
    for(int i = 0; i < n; i++)
    {
        cin >> str;
        
        root->insert(str.c_str());
    }
    
    int cnt = 0;
    for(int i = 0; i < m; i++)
    {
        cin >> str;
        
        if(root->find(str.c_str()))
        {
            cnt++;
        }
    }
    
    cout << cnt << endl;
    delete root;
    return 0;
}

'Algorithm' 카테고리의 다른 글

[백준 16926] 배열 돌리기1  (0) 2021.10.12
[백준 17298] 오큰수  (0) 2021.10.11
[백준 1753] 최단경로  (0) 2021.10.11
[HackerRank] 2D Array - DS  (0) 2021.09.09
[프로그래머스] 방문 길이 (C++)  (0) 2021.06.04

+ Recent posts