Leetcode (4) | | Longest palindromic Substring and manacher linear algorithmPreface
This article is the fifth question of Leetcode, did not think that the speed of doing these questions will be so slow, all of the work in this above, the only blame their basic poor. This article mainly describes the longest palindrome substring used to solve a string using the Manacher linear algorithm.
Topics
Given a string S, find the longest palindromic substring in s. The maximum length of S is assume, and there exists one unique longest palindromic substring.
Thinking of solving problems
- The topic meaning is relatively simple, assuming that the string s maximum length is 1000, the longest palindrome string of the string is calculated. Assume that there is a unique, longest palindrome string.
- Palindrome There are two cases, the first kind of "ABA", the Second "ABBA", if there is no more effective method, in the subsequent solution of these two situations will greatly increase the difficulty of solving problems. The Manacher algorithm uses a more efficient method. Assuming that the character ' # ' does not appear in S, insert ' # ' into the string s, such as "ABA", "#a #b#a#", "ABBA" and "#a #b#b#a#", so that the two cases are cleverly solved together.
1 Public Char[] expandstring (String s) {2 intLen =s.length ();3 Char[] cs =New Char[Len*2+3];4 for(inti = 0; i < Len; i++){5cs[2*i+1]= ' # ';6cs[2*i+2]=S.charat (i);7 }8cs[0]= ' * ';9cs[2*len+1]= ' # ';Tencs[2*len+2]= '? '; One returnCS; A } - PublicString shrinkstring (Char[] CS) { - intLen =cs.length; the Char[] Shrinkchars =New Char[Len]; - intJ=0; - for(inti = 0; I < len;i++){ - if(cs[i]! = ' # '){ +Shrinkchars[j++] =Cs[i]; - } + } A return NewString (shrinkchars). Trim (); at}
- The most violent thing to solve this problem is to use two for loops, computational complexity at O (N2), we first ruled out this barbaric method, otherwise it would be meaningless to do the problem.
- The method I think of is a method of calculating the complexity in O (N*log (n)), and the method is as follows:
- Traversing the string s, assuming that the current position is I, will I go to both sides of the traversal, using palindrome on the characteristics of the emphasis symmetry to retrieve the text, while (Cs[i+j]==cs[i-j]) j + +;
- Here the array p is the longest palindrome radius that holds the current position, and the manacher linear algorithm that constructs the context.
Publicstring Longestpalindrome (string s) {Char[] cs =expandstring (s); intLen =cs.length; int[] p =New int[Len]; intMax = 0; for(inti = 1; I <len-1; i++) {P[i]=1; while(Cs[i+p[i]]==cs[i-p[i]]) p[i]++; if(P[i] >P[max]) {Max=i; } } intLenmax =P[max]; Char[] result =New Char[2*lenmax-1]; Result[lenmax-1] =Cs[max]; for(inti = 1; i < Lenmax; i++) {Result[i+LENMAX-1] = cs[max+i]; Result[lenmax-1-i] = cs[max+i]; } returnshrinkstring (Result); }
- Although the second method solves the maximum palindrome string in the Leecode, but in the solution process due to repeated solution or wasted a lot of time, such as s= "Abababa", S is about s[3] palindrome, when traversing s[1], because of the symmetry relationship S[5] Part of the palindrome has been established, So there is no need to s[4] to s[6] and there is no need to traverse, just complete the mapping. This is the core of the Manacher linear algorithm, Manacher linear algorithm to the maximum extent the use of palindrome characteristics, the algorithm content is described in the following.
Manacher linear algorithm
The specific Manacher linear algorithm is described in the longest palindrome substring (longest palindromic Substring).
Using an auxiliary array arr[n], where arr[i] records the length of a palindrome substring centered on str[i]. When calculating arr[i], arr[0...i-1] is known and can be exploited. The core of Manacher lies in: The last boundary that can be reached by the longest palindrome string length computed before the MX record, the corresponding center can be recorded with ID, and the palindrome substring information in the palindrome string may be used.
Assuming that the ID and MX have been obtained, when the calculation with Str[i] as the central palindrome string length, because it can be determined that the green part is already a palindrome string, so you can use the STR[J] as the center palindrome string length is arr[j]. In the case, you can start the comparison as indicated by the arrows. There is another situation:
In this case, you can not directly take advantage of STR[J] as the center palindrome substring length is arr[j], because the ID-centered palindrome string length is only calculated to the green arrow points, so the ability to use the information is mx-i, compare the characters after mx-i.
The Manacher algorithm code is as follows:
1 Publicstring Longestpalindromeone (string s) {2 3 Char[] cs =expandstring (s);4 intLen =cs.length;5 int[] p =New int[Len];6 intID = 0;7 intMax = 0;8 for(inti = 1; I <len-1; i++){9 if(I < p[id]+ID) {TenP[i]=math.min (P[id]+id-i, p[2*id-i]); One}Else{ AP[i]=1; - } - the while(Cs[i+p[i]]==cs[i-p[i]]) p[i]++; - - if(P[i]+i> p[id]+ID) { -ID =i; + } - + if(P[i] >P[max]) { AMax =i; at } - - } - - intLenmax =P[max]; - Char[] result =New Char[2*lenmax-1]; inRESULT[LENMAX-1] =Cs[max]; - for(inti = 1; i < Lenmax; i++){ toRESULT[I+LENMAX-1] = cs[max+i]; +Result[lenmax-1-i] = cs[max+i]; - } the * returnshrinkstring (result); $}
About the Manacher algorithm to add a few points:
- To prevent traversal while (Cs[i+p[i]]==cs[i-p[i]) p[i]++, you need to process the string, add the character ' * ' to the string s[0], add the character ' '? ' at the end of the string, and the house because S itself is a palindrome and make the traversal error.
- The array p represents the palindrome radius of the character, such as s= "#a #b#c#g#c#h" array is p= "121212141211", S[7]=g's palindrome radius is p[7]=4
- The ID represents the number of the center character of the previous postback string, then P[id] is the radius of the previous back-word character. For example, when I=8, the previous palindrome string is "#c #g#c#", p[id]=4.
- P[i]=math.min (P[id]+id-i, p[2*id-i]); That is, if I is within the radius of the previous back string (that is, I < p[id]+id), I to the two farthest boundary of the back character (due to the return literal character about the ID position symmetry, leftmost p[2*id-i], and the rightmost p[id]+id-i) The minimum distance is math.min (p[id]+id-i, P[2*id-i]). Depending on the symmetric relationship, if the elements I to math.min (P[id]+id-i, p[2*id-i]) do not need to be traversed, just start the subsequent palindrome check directly from Math.min (P[id]+id-i, P[2*id-i]) while (cs[i+p[ I]]==cs[i-p[i]]) p[i]++;. The benefit of this is that the repetitive steps are greatly reduced and the computational complexity is reduced.
- Each ID corresponds to a palindrome string, and the longest palindrome string can be obtained as long as the maximum ID is p[id during the record traversal.
Leetcode (4) | | Longest palindromic Substring and manacher linear algorithm