
N이 20,000으로 크기 때문에, 단순히 단어끼리의 비교를 하는데만 시간복잡도가 O(N^2)인데다가 접두사를 비교하게되면 최악으로는 단어길이 100이 곱해지기 때문에 불가능하다 판단하였다.
시간내에 통과하기 위해서는 S = 단어길이라고 했을 때, 시간복잡도는 리니어하거나 최대 로그 시간복잡도를 가진 O(N*S) ~ O(N*logN*S)가 되어야했다.
1. 이분탐색
각 단어별로 알파벳 순으로 정렬된 단어배열에서 접두사를 비교하는 방법을 생각해보았다. 하지만 단어의 길이에 따른 출력이 아닌 입력순으로 출력이 되어야하기 때문에, 정렬 후 탐색하면서도 입력순서도 고려해야했기에는 탐색이 너무 복잡해진다 생각했다. 따라서, 다른 방법을 찾아보았다.
2. 접두사 맵
각 단어끼리의 접두사 비교는 단어가 입력될 때마다 이전 단어에 대해 수행이 되면 된다. 다만, 모든 단어에 대해 연산을 하면 시간복잡도가 O(N^2)이 된다. 그렇기에 지금까지 입력된 단어 중에 동일한 접두사를 가졌었는지 확인하는 효율적인 방법이 필요했고, O(1)로 확인이 가능한 Map을 사용했다.
단어가 입력될 때마다 가장 긴 접두사(부분문자열)부터 Map에 접두사가 저장되어 있는지 확인한다:
Map에 부분문자열과 함께 현재 단어를 저장한다.S보다 빠르다면:Map에 저장된 접두사의 원본 단어가 ST입력된 순서는 단어별로 바로 탐색이 가능하도록 별도의 Map으로 관리한다.
Map으로 인해 메모리 사용량이 높을 수 있지만, 그 대가로 O(N*S) 수준의 리니어한 수행속도를 보장한다.
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
solve(in);
}
static void solve(BufferedReader in) throws IOException {
int cnt = Integer.parseInt(in.readLine());
Map<String, Integer> order = new HashMap();
Map<String, String> map = new HashMap<>();
int max = 0;
String first = "";
String second = "";
for(int i = 0; i < cnt; i++) {
String str = in.readLine();
if(!order.containsKey(str)) order.put(str, i);
for(int s = str.length(); s > 0; s--) {
String sub = str.substring(0, s);
if(!map.containsKey(sub)) map.put(sub, str);
else {
if(!map.get(sub).equals(str)
&& (sub.length() > max
|| (sub.length() == max && order.get(map.get(sub)) < order.get(first)))) {
first = map.get(sub);
second = str;
max = sub.length();
}
break;
}
}
}
System.out.println(first);
System.out.println(second);
}
}