How to find the longest palindrome prefix of a string in O(n)?
Asked
Active
Viewed 7,703 times
8
-
5This sounds like a homework question. If so it should be tagged as such. – Philip Starhill Sep 30 '10 at 17:18
-
1Define longest palindrome prefix. And should the time be bound by O(n) or memory too? And is this homework? – Dirk Vollmar Sep 30 '10 at 17:20
-
2I think this answer is a toyota – Chris S Sep 30 '10 at 18:24
-
Have a Left pointer and a Right pointer and a LPal pointer. If S[Left] == S[Right], advance the Left pointer, decrement the Right pointer. Otherwise, Set Left pointer to 0, decrement right pointer, set LPal to right pointer. If Left == Right, return. LPal will be the last index of the longest palindromic prefix. – mk3009hppw Aug 03 '20 at 06:31
3 Answers
9
Use a rolling hash. If a
is your string, let ha[x]
be the hash of the first x
chars in a
computed from left to right and let hr[x]
be the hash of the first x
characters in s
computed from right to left. You're interested in the last position i
for which hf[i] = hb[i]
.
Code in C (use two hashes for each direction to avoid false positives):
int match = n - 1;
int ha1 = 0, ha2 = 0, hr1 = 0, hr2 = 0;
int m1 = 1, m2 = 1;
for ( int i = 0; a[i]; ++i )
{
ha1 = (ha1 + m1*a[i]) % mod1;
ha2 = (ha2 + m2*a[i]) % mod2;
hr1 = (a[i] + base1*hr1) % mod1;
hr2 = (a[i] + base2*hr2) % mod2;
m1 *= base1, m1 %= mod1;
m2 *= base2, m2 %= mod2;
if ( ha1 == hr1 && ha2 == hr2 )
match = i;
}

IVlad
- 43,099
- 13
- 111
- 179
-
I think the 'from right to left' part isn't there in the code example... (`i` goes from left to right and you're only accessing `a[i]`. – Andre Holzner Sep 30 '10 at 21:38
-
@Andre Holzner - `i` goes only from left to right. At each step `i`, you will have the length of the current longest palindromic prefix stored in `match`. It's only the rolling hashes that go both ways. – IVlad Sep 30 '10 at 21:51
-
+1, I didn't know it was called 'rolling hash'. But I even two hashes doesn't guarantee that every positive is 'true' (not to mention, with such unusual coefficients :)). Simply because for some length _n_ there're more n-character strings than different pairs of int numbers _(ha1, ha2)_. And if you do the verify each positive, you get O(n^2) on uniform string ('aaaaaaaa...'). – Nikita Rybak Sep 30 '10 at 23:50
-
What you can do is store all hashes on the first pass into array and then start from the longest candidate (whole string), reducing it char by char. In this case, if you get verified positive, program is finished: you've found longest palindrome-prefix. And since your two hashes have rare enough false positives, program is still 'kinda' O(n) for reasonable values of _n_. – Nikita Rybak Sep 30 '10 at 23:52
-
Ivlad, I don't see how any of `ha1`, `ha2`, `hr1` or `hr2` are calculated from right to left. In each loop iteration, only the next element to the right (`a[i]`) is processed. – Andre Holzner Oct 01 '10 at 06:20
-
@Andre Holzner - try building `ha1` and `hr1` step by step. At `i = 0`, we have `ha1 = a[0]` and `hr1 = a[0]`. If the two are equal (obviously they will be), we have a 1 character long palindromic prefix. At `i = 1`, we have `ha1 = a[0] + base1*a[1]` and `hr1 = a[1] + a[0]*base1`. Do you see where this is going and what I meant by `left to right` and `right to left` now? Try building `ha1` and `hr1` for `i = 2` as well. @Nikita Rybak - true, no guarantees. – IVlad Oct 01 '10 at 09:29
0
Solution for a more general problem, not prefix but sub-string, in O(n) :
http://www.akalin.cx/2007/11/28/finding-the-longest-palindromic-substring-in-linear-time/
Second result on google for "longest palindrome prefix"....
Or solution using suffix-trees :

Loïc Février
- 7,540
- 8
- 39
- 51
-
Has the function `fastLongestPalindromes(..)` on the link to akalin.cx actually `O(n)` worst case complexity ? I see two nested loops.. – Andre Holzner Oct 01 '10 at 20:01
-
Haven't read everything but 2 nested loops does not mean quadratic complexity. The continue at the beginning of the function should ensure that the inner loop in only executed in a few cases and that the overall complexity of each execution of that loop is O(n). – Loïc Février Oct 01 '10 at 21:31
0
Using z-algorithm (https://codeforces.com/blog/entry/3107). Suppose s is the given string of length m. Code:
string rev="",str=s;
int m=s.size(),longestPalindromicPrefix=1;
if(m==0 || m==1) longestPalindromicPrefix=m;
for(int i=m-1;i>=0;i--)
rev+=s[i];
s+='#';
s+=rev;
int n=s.size(),z[n+4],l=0,r=0;
for(int i=1;i<n;i++){
if(i>r){
l=r=i;
while(r<n && s[r-l]==s[r])
r++;
z[i]=r-l,r--;
}
else{
int k=i-l;
if(z[k]<r-i+1)
z[i]=z[k];
else{
l=i;
while(r<n && s[r-l]==s[r])
r++;
z[i]=r-l,r--;
}
}
}
for(int i=m+1;i<n;i++){
if(2*z[i]>=2*m-i && z[i]>longestPalindromicPrefix)
longestPalindromicPrefix=z[i];
}