주어진 문자열의 부분 문자열 중 회문인 것의 개수를 구하는 문제를 풀어봤다. 이 문제는 문자열 길이가 최대 200만까지 가능하므로 모든 부분 문자열을 탐색하는 브루트포스 방식으로는 시간 초과가 발생할 수 있다. 그래서 Manacher's 알고리즘을 활용해 문제를 해결했다. Manacher's 알고리즘은 문자열에서 모든 회문의 길이를 O(n)의 시간 복잡도로 찾을 수 있는 효율적인 알고리즘이다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input = br.readLine().trim();
// 문자열을 #으로 구분하여 새로운 문자열 생성
StringBuilder sb = new StringBuilder("#");
for (char c : input.toCharArray()) {
sb.append(c).append("#");
}
String modifiedString = sb.toString();
System.out.println(manachers(modifiedString));
}
public static long manachers(String s) {
int n = s.length();
int[] A = new int[n]; // 각 중심에서 확장되는 회문의 길이를 저장하는 배열
int r = 0, p = 0; // r: 가장 오른쪽까지 뻗은 회문의 끝, p: 그 중심
long result = 0; // 총 회문 개수
for (int i = 0; i < n; i++) {
// 회문의 길이 대칭성 활용
if (i <= r) {
A[i] = Math.min(A[2 * p - i], r - i);
}
// 회문 확장
while (i - A[i] - 1 >= 0 && i + A[i] + 1 < n && s.charAt(i - A[i] - 1) == s.charAt(i + A[i] + 1)) {
A[i]++;
}
// 가장 오른쪽 회문 업데이트
if (r < i + A[i]) {
r = i + A[i];
p = i;
}
// 각 중심에서 구해진 회문의 절반 크기만큼 회문 개수를 누적
result += (A[i] + 1) / 2;
}
return result;
}
}
StringBuilder sb = new StringBuilder("#");
for (char c : input.toCharArray()) {
sb.append(c).append("#");
}
String modifiedString = sb.toString();
public static long manachers(String s) {
int n = s.length();
int[] A = new int[n]; // 각 중심에서 확장되는 회문의 길이를 저장하는 배열
int r = 0, p = 0; // r: 가장 오른쪽까지 뻗은 회문의 끝, p: 그 중심
long result = 0; // 총 회문 개수
if (i <= r) {
A[i] = Math.min(A[2 * p - i], r - i);
}
while (i - A[i] - 1 >= 0 && i + A[i] + 1 < n && s.charAt(i - A[i] - 1) == s.charAt(i + A[i] + 1)) {
A[i]++;
}
if (r < i + A[i]) {
r = i + A[i];
p = i;
}
result += (A[i] + 1) / 2;
Manacher's 알고리즘을 활용하여 효율적으로 주어진 문자열 내 부분 문자열 중 회문인 것의 개수를 구할 수 있었다. 이 알고리즘을 사용하지 않고 모든 부분 문자열을 탐색하면 O(n^2)~O(n^3) 복잡도가 될 수 있어 시간 초과가 발생했을 것이다. Manacher's 알고리즘의 대칭성을 활용하여 O(n)으로 해결한 것이 핵심이었다.