Ejercicios de algoritmo: algoritmo de Manacher
- Ejercicio 1 Suponga que la longitud de la cadena str es N. Si desea devolver la longitud de la subcadena palíndromo más larga, la complejidad temporal es O (N).
- Ejercicio 2: dados los nodos principales head1 y head2 de dos árboles binarios, desea saber si hay un subárbol en head1 que tenga la misma estructura que head2.
Núcleo del algoritmo de administrador
1) Comprender la matriz de radio palíndromo
2) Comprenda el límite R más a la derecha del palíndromo de todos los centros y el punto central C al obtener R
3) Comprender la estructura de L...(i`)...C...(i)...R, y la división de situaciones según la longitud del palíndromo i'.
4) Cada situación se puede dividir para acelerar el proceso de resolución del radio palíndromo i.
Ejercicio 1 Suponga que la longitud de la cadena str es N. Si desea devolver la longitud de la subcadena palíndromo más larga, la complejidad temporal es O (N).
public static int manacher(String s) {
if (s == null || s.length() == 0) {
return 0;
}
// "12132" -> "#1#2#1#3#2#"
char[] str = manacherString(s);
// 回文半径的大小
int[] pArr = new int[str.length];
int C = -1;
// 讲述中:R代表最右的扩成功的位置
// coding:最右的扩成功位置的,再下一个位置
int R = -1;
int max = Integer.MIN_VALUE;
for (int i = 0; i < str.length; i++) { // 0 1 2
// R第一个违规的位置,i>= R
// i位置扩出来的答案,i位置扩的区域,至少是多大。
pArr[i] = R > i ? Math.min(pArr[2 * C - i], R - i) : 1;
while (i + pArr[i] < str.length && i - pArr[i] > -1) {
if (str[i + pArr[i]] == str[i - pArr[i]])
pArr[i]++;
else {
break;
}
}
if (i + pArr[i] > R) {
R = i + pArr[i];
C = i;
}
max = Math.max(max, pArr[i]);
}
return max - 1;
}
public static char[] manacherString(String str) {
char[] charArr = str.toCharArray();
char[] res = new char[str.length() * 2 + 1];
int index = 0;
for (int i = 0; i != res.length; i++) {
res[i] = (i & 1) == 0 ? '#' : charArr[index++];
}
return res;
}
// for test
public static int right(String s) {
if (s == null || s.length() == 0) {
return 0;
}
char[] str = manacherString(s);
int max = 0;
for (int i = 0; i < str.length; i++) {
int L = i - 1;
int R = i + 1;
while (L >= 0 && R < str.length && str[L] == str[R]) {
L--;
R++;
}
max = Math.max(max, R - L - 1);
}
return max / 2;
}
// for test
public static String getRandomString(int possibilities, int size) {
char[] ans = new char[(int) (Math.random() * size) + 1];
for (int i = 0; i < ans.length; i++) {
ans[i] = (char) ((int) (Math.random() * possibilities) + 'a');
}
return String.valueOf(ans);
}
public static void main(String[] args) {
int possibilities = 5;
int strSize = 20;
int testTimes = 5000000;
System.out.println("test begin");
for (int i = 0; i < testTimes; i++) {
String str = getRandomString(possibilities, strSize);
if (manacher(str) != right(str)) {
System.out.println("Oops!");
}
}
System.out.println("test finish");
}
Ejercicio 2: dados los nodos principales head1 y head2 de dos árboles binarios, desea saber si hay un subárbol en head1 que tenga la misma estructura que head2.
public static String shortestEnd(String s) {
if (s == null || s.length() == 0) {
return null;
}
char[] str = manacherString(s);
int[] pArr = new int[str.length];
int C = -1;
int R = -1;
int maxContainsEnd = -1;
for (int i = 0; i != str.length; i++) {
pArr[i] = R > i ? Math.min(pArr[2 * C - i], R - i) : 1;
while (i + pArr[i] < str.length && i - pArr[i] > -1) {
if (str[i + pArr[i]] == str[i - pArr[i]])
pArr[i]++;
else {
break;
}
}
if (i + pArr[i] > R) {
R = i + pArr[i];
C = i;
}
if (R == str.length) {
maxContainsEnd = pArr[i];
break;
}
}
char[] res = new char[s.length() - maxContainsEnd + 1];
for (int i = 0; i < res.length; i++) {
res[res.length - 1 - i] = str[i * 2 + 1];
}
return String.valueOf(res);
}
public static char[] manacherString(String str) {
char[] charArr = str.toCharArray();
char[] res = new char[str.length() * 2 + 1];
int index = 0;
for (int i = 0; i != res.length; i++) {
res[i] = (i & 1) == 0 ? '#' : charArr[index++];
}
return res;
}
public static void main(String[] args) {
String str1 = "abcd123321";
System.out.println(shortestEnd(str1));
}