Question: Longest Palindromic Substring Length
For example, the length of the longest palindrome substring in 122131221 is 4
Classic solution:
Traverse each character, expand to both sides and check the longest palindrome substring
But this alone cannot find palindrome substrings of even length
So it needs to be transformed into #1#2#2#1#3#1#2#2#1#
The maximum palindrome substring length of this new string is divided by 2 and rounded to get the maximum palindrome substring length of the original string
Question extension: Does the inserted special character # need to be a character that does not appear in the string?
Answer: No need. Because the comparison is always whether the special characters are equal to the special characters, the characters in the original string are compared
Classical solution time complexity: O( N 2 N^2N2)
Manager: O(N)
Clear concept: palindrome diameter + palindrome radius
For example: #1#2#1# has a palindrome diameter of 7 and a palindrome radius of 4
Each character in a string has a corresponding palindrome diameter and palindrome radius, we need to traverse all characters to generate a palindrome radius array
In the process of generating the palindrome radius, a variable R is maintained to record the rightmost boundary of the generated palindrome substring ; a variable C is also maintained to record the center of the palindrome substring
For example: arr={#,1,#,2,#,1,#,...}
R and C are initially -1, representing the out-of-bounds position
traversal start
For arr[0]=='#', the palindrome range is 0~0, R<0, so update R to 0 and update C to 0
For arr[1]=='1', the palindrome range is 0~2, R<2, so update R to 2 and C to 1
For arr[2]=='#', the palindrome range is 2~2, R=2, so R and C are not updated
···
As long as the palindrome radius array and R, C are generated, the solution can be obtained
The manacher algorithm is a violence-based optimization of this process
Come to the i position, determine the palindrome radius and diameter according to the situation:
1. If i>R, that is, i is the first time to come to the position, then the violence will expand to both sides, looking for the palindrome radius of the substring centered on arr[i]; 0, 1, 3 in the above example This is the case for the location
2. If i<=R, it can be optimized, and it must be the following:
At this time, i' and i are symmetrical about C, and the boundaries of the palindrome substring centered on C are L and R
L i' C i R
i is on the left side of R, then C must be on the left side of i (think about the counterargument, note that C is the position that has been traversed), and the corresponding L can be found, and the symmetric point of i about C can also be found
2, 4, 5, and 6 in the above example are all like this
The following is classified according to the palindrome of i':
1) The palindrome substring centered on i' is completely within the range from L to R, then the palindrome radius of i is the same as that of i' (L to R is symmetric about C, so it is obvious), and it does not expand i got the answer directly
2) Part of the palindrome substring centered on i' is outside [L, R], for example:
(ab[cd e dcba) k abcd e dc]ft
L i' C i R
Then the palindrome radius of the palindrome substring centered on i is R-i+1, which will not be larger, and the answer can be obtained directly without expanding i
3) The left boundary of the palindrome substring centered on i' coincides with L
like:
[(abc d cba) k abc d cba]
i' C i
Then the minimum range of the palindrome substring centered on i is already abc d cba, and it needs to be expanded violently
complete
According to the code, the time complexity can be analyzed as O(N)
public static int manacher(String s) {
if (s == null || s.length() == 0) return 0;
char[] str = manacherString(s); // 1221->#1#2#2#1#
int[] pArr = new int[str.length]; // 回文半径数组
int R = -1, C = -1, max = Integer.MAX_VALUE; // R是回文右边界再往右一个位置,不同于笔记
for (int i = 0; i < str.length; i++) {
// 得到不用扩展就已经知道的以i为中心的回文区域
// 大情况1:初始直径为1,需要往外暴力扩展
// 小情况1:中心为i'的回文直径长度,不需要扩展
// 小情况2:半径为R-i+1,不需要扩展
// 小情况3:中心为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; // 半径减1正好是原始s的回文子串长度(不用除以2了)
}
public static char[] manacherString(String s) {
char[] charArr = s.toCharArray();
char[] res = new char[s.length() * 2 + 1];
int index = 0;
for (int i = 0; i != res.length; i++) {
res[i] = (i % 2) == 0 ? '#' : charArr[index++];
}
return res;
}
Palindromic radius arrays can be used for many problems