To talk about the horse-drawn cart algorithm, you must talk about this problem, find the longest palindrome substring. The horse-drawn cart algorithm is one of the solutions.
Title description
Give you a string s and find the longest palindrome substring in s.
example
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
示例 3:
输入:s = "a"
输出:"a"
示例 4:
输入:s = "ac"
输出:"a"
Horse-drawn cart algorithm
This is a wonderful algorithm, invented by a man named Manacher in 1957, so it is called Manacher‘s Algorithm
. It is mainly used to find the longest palindrome substring of a string. The biggest contribution of this algorithm is to increase the time complexity to linear , The time complexity of the dynamic programming we mentioned earlier is O(n 2 ).
In the center expansion method mentioned earlier, the center may be a character or a character gap, so if there are n characters, there will be n+n+1
centers:
In order to solve the above said center gap may be the problem, we insert "to each character gap #
", in order to allow expansion of the end of the boundary more clearly, border the left into the " ^
", insert the right side of the border " $
":
S
means inserting #
", " ^
"," $
", and we use an array P
represent the S
of each character in 06169a58b4f566 that can be extended on both sides:
For example, P[8] = 3
, which means that you can extend 3 characters on both sides, that is, the length of the palindrome is 3 , and the string after #
aca
:
P[11]= 4
, which means that you can extend 4 characters on both sides, that is, the length of the palindrome is 4 , and the string after #
caac
:
Assuming that we already know the array P, how do we get the palindrome?
With P
subscripts index
, subtracting P[i]
(i.e. palindromic string length) can be obtained at the beginning of a string of characters in the string palindrome after expansion S
the subscript, divided by 2, can be obtained in the original string The subscript is out.
So the question now is: How to solve the array P[i]
In fact, the key to the horse-drawn cart algorithm is: It makes full use of the symmetry of the palindrome and uses the existing results to help calculate the subsequent results.
Assuming that the largest palindrome at the character index position P has been calculated, the left boundary is P L , and the right boundary is P R :
So when we ask because a position i
time, i
less P R , in fact, we can find i
on P
symmetrical point j
:
Then suppose the length of the longest palindrome with j as the center is len, and within L to P, the same is true for the longest palindrome with i as the center:
length of the longest palindrome substring centered on i is equal to the length of the longest palindrome substring centered on j
But there are two problems here:
- Which one is the previous palindrome string P?
- What are the special circumstances? How to deal with special circumstances?
(1) The previous palindrome string P
refers to the on the right edge calculated earlier, because it is most likely to cover the i-centered index we are calculating now, so it can be reused as much as possible Symmetry of previous results.
Because of this, when we calculate, we need to keep updating the center and right boundary of P for every calculation.
(2) The special case is that the calculation of the longest palindrome string of current i can no longer use the symmetry of point P, for example:
- The right boundary of the palindrome with
i
P
P R :
The solution to this situation is: the excess parts need to be expanded one by one according to the central expansion method.
i
not inP
, and can only be processed in accordance with the central expansion method.
The specific code implementation is as follows:
// 构造字符串
public String preProcess(String s) {
int n = s.length();
if (n == 0) {
return "^$";
}
String ret = "^";
for (int i = 0; i < n; i++)
ret = ret + "#" + s.charAt(i);
ret = ret + "#$";
return ret;
}
// 马拉车算法
public String longestPalindrome(String str) {
String S = preProcess(str);
int n = S.length();
// 保存回文串的长度
int[] P = new int[n];
// 保存边界最右的回文中心以及右边界
int center = 0, right = 0;
// 从第 1 个字符开始
for (int i = 1; i < n - 1; i++) {
// 找出i关于前面中心的对称
int mirror = 2 * center - i;
if (right > i) {
// i 在右边界的范围内,看看i的对称点的回文串长度,以及i到右边界的长度,取两个较小的那个
// 不能溢出之前的边界,否则就得中心拓展
P[i] = Math.min(right - i, P[mirror]);
} else {
// 超过范围了,中心拓展
P[i] = 0;
}
// 中心拓展
while (S.charAt(i + 1 + P[i]) == S.charAt(i - 1 - P[i])) {
P[i]++;
}
// 看看新的索引是不是比之前保存的最右边界的回文串还要靠右
if (i + P[i] > right) {
// 更新中心
center = i;
// 更新右边界
right = i + P[i];
}
}
// 通过回文长度数组找出最长的回文串
int maxLen = 0;
int centerIndex = 0;
for (int i = 1; i < n - 1; i++) {
if (P[i] > maxLen) {
maxLen = P[i];
centerIndex = i;
}
}
int start = (centerIndex - maxLen) / 2;
return str.substring(start, start + maxLen);
}
As for the complexity of the algorithm, the space complexity uses an array of size n, which is O(n), and the time complexity, which seems to use two loops, is not O(n 2 ), but O(n)
, Because most index positions will directly use the previous results and symmetry to obtain the results, and the results can be obtained at constant times, and those that require center expansion are beyond the coverage of the previous results, so they need to be expanded and expanded. , Which is conducive to the calculation of the next index position, so the expansion is actually less.
[Profile of the author] :
Qin Huai, Qinhuai Grocery Store ], the road to technology is not at a time, the mountains are high and the rivers are long, even if it is slow, it will never stop. Personal writing direction: Java source code analysis,
JDBC
, Mybatis
, Spring
, redis
, distributed,
sword refers to writing a series of offers, every article in the series of
LeetCode
, I cannot guarantee that what I have written is completely correct, but I guarantee that what I have written has been practiced or searched for information. I hope to correct any omissions or errors.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。