문제 소개
단어 목록이 주어지면, 참조 문자열(reference string) S와 인덱스 리스트 A를 작성하여 이를 인코딩할 수 있습니다. 예를 들어 단어 목록이 ["time", "me", "bell"]이라면, S = "time#bell#"이고 indexes = [0, 2, 5]로 표현할 수 있습니다. 각 인덱스 위치에서는 참조 문자열을 해당 지점부터 "#" 기호를 만날 때까지 읽어 원래 단어를 복원합니다.
따라서 우리가 구해야 하는 것은 주어진 단어들을 모두 인코딩할 수 있는 가장 짧은 참조 문자열 S의 길이입니다. 위 예제에서 정답은 10입니다.
접근 방법: 트라이(Trie) 활용
이 문제는 트라이(Trie) 자료구조를 활용하면 효율적으로 해결할 수 있습니다. 핵심 아이디어는 다음과 같습니다.
- 단어들을 길이 기준으로 내림차순 정렬합니다.
- 각 단어를 뒤에서부터(역순으로) 트라이에 삽입합니다.
- 삽입 과정에서 새로운 노드가 생성되었다면, 그 단어는 다른 단어의 접미사가 아니므로 인코딩 길이에 포함해야 합니다.
- 새 노드가 하나도 생성되지 않았다면, 해당 단어는 이미 삽입된 더 긴 단어의 접미사이므로 별도로 인코딩할 필요가 없습니다.
길이가 긴 단어를 먼저 처리하면, 접미사 관계에 있는 짧은 단어들이 자동으로 걸러지기 때문에 최적의 결과를 얻을 수 있습니다. 또한 각 단어 뒤에는 반드시 "#" 구분 기호가 붙으므로, 유효한 단어마다 길이에 1을 더해주어야 합니다.
알고리즘 단계
insertNode메서드를 정의합니다. 이 메서드는 head 노드와 문자열 s를 매개변수로 받습니다.- curr := head, flag := false로 초기화합니다.
- i를 s.size() - 1부터 0까지 감소시키며 반복합니다.
- x := s[i]
- curr의 m[x]가 null이면 flag := true로 설정하고 새 노드를 생성하여 curr의 m[x]에 저장합니다.
- curr := curr의 m[x]로 갱신합니다.
- flag가 true이면 s의 크기를 반환하고, 그렇지 않으면 0을 반환합니다.
- 메인 메서드에서는 다음을 수행합니다.
- ret := 0, head := 새 노드로 초기화합니다.
- words 배열을 길이 기준으로 내림차순 정렬합니다.
- n := words의 크기
- i를 0부터 n-1까지 반복합니다.
- temp := insertNode(head, words[i])
- temp가 0이 아니면 ret := ret + temp + 1
- ret을 반환합니다.
C++ 구현 예제
#include <bits/stdc++.h>
using namespace std;
struct Node{
map <char, Node*> m;
};
class Solution {
public:
static bool cmp(string a, string b){
return a.size() > b.size();
}
int insertNode(Node* head, string s){
Node* curr = head;
bool flag = false;
for(int i = s.size() - 1; i >= 0; i--){
char x = s[i];
if(!curr->m[x]){
flag = true;
curr->m[x] = new Node();
}
curr = curr->m[x];
}
return flag? (int)s.size() : 0;
}
int minimumLengthEncoding(vector<string>& words) {
int ret = 0;
Node* head = new Node();
sort(words.begin(), words.end(), cmp);
int n = words.size();
for(int i = 0; i < n; i++){
int temp= insertNode(head, words[i]);
if(temp){
ret += (temp + 1);
}
}
return ret;
}
};
main(){
vector<string> v = {"time", "me", "bell"};
Solution ob;
cout << (ob.minimumLengthEncoding(v));
}실행 결과
입력:
["time", "me", "bell"]
출력:
10
복잡도 분석
시간 복잡도는 단어 정렬에 O(N log N · L)(N은 단어 개수, L은 평균 단어 길이), 트라이 삽입에는 전체 문자 수에 비례하는 O(ΣL)이 소요되므로 전체적으로 O(N log N · L + ΣL)입니다. 공간 복잡도는 트라이에 저장되는 노드 수에 비례하여 O(ΣL)입니다.