If the input is 'abba' then the possible palindromes are a, b, b, a, bb, abba.
I understand that determining if string is palindrome is easy. It would be like:
public static boolean isPalindrome(String str) {
int len = str.length();
for(int i=0; i<len/2; i++) {
if(str.charAt(i)!=str.charAt(len-i-1) {
return false;
}
return true;
}
But what is the efficient way of finding palindrome substrings?
I just came up with my own logic which helps to solve this problem. Happy coding.. :-)
I tried the following code and its working well for the cases Also it handles individual characters too
Few of the cases which passed:
Code
Hope its fine
So, each distinct letter is already a palindrome - so you already have N + 1 palindromes, where N is the number of distinct letters (plus empty string). You can do that in single run - O(N).
Now, for non-trivial palindromes, you can test each point of your string to be a center of potential palindrome - grow in both directions - something that Valentin Ruano suggested.
This solution will take O(N^2) since each test is O(N) and number of possible "centers" is also O(N) - the
center
is either a letter or space between two letters, again as in Valentin's solution.Note, there is also O(N) solution to your problem, based on Manacher's algoritm (article describes "longest palindrome", but algorithm could be used to count all of them)
This can be done in
O(n)
, using Manacher's algorithm.The main idea is a combination of dynamic programming and (as others have said already) computing maximum length of palindrome with center in a given letter.
What we really want to calculate is radius of the longest palindrome, not the length. The radius is simply
length/2
or(length - 1)/2
(for odd-length palindromes).After computing palindrome radius
pr
at given positioni
we use already computed radiuses to find palindromes in range[
i - pr ; i
]
. This lets us (because palindromes are, well, palindromes) skip further computation ofradiuses
for range[
i ; i + pr
]
.While we search in range
[
i - pr ; i
]
, there are four basic cases for each positioni - k
(wherek
is in1,2,... pr
):radius = 0
) ati - k
(this means
radius = 0
ati + k
, too)(this means
radius
ati + k
is the same as ati - k
)(this means
radius
ati + k
is cut down to fit in range, i.e becausei + k + radius > i + pr
we reduceradius
topr - k
)i + k + radius = i + pr
(in that case we need to search for potentially bigger radius at
i + k
)Full, detailed explanation would be rather long. What about some code samples? :)
I've found C++ implementation of this algorithm by Polish teacher, mgr Jerzy Wałaszek.
I've translated comments to english, added some other comments and simplified it a bit to be easier to catch the main part.
Take a look here.
Note: in case of problems understanding why this is
O(n)
, try to look this way:after finding radius (let's call it
r
) at some position, we need to iterate overr
elements back, but as a result we can skip computation forr
elements forward. Therefore, total number of iterated elements stays the same.Try out this. Its my own solution.