Leetcode – Longest Palindromic Substring (Java)

Finding the longest palindromic substring is a classic problem of coding interview. This post summarizes 3 different solutions for this problem.

1. Dynamic Programming

Let s be the input string, i and j are two indices of the string. Define a 2-dimension array "table" and let table[i][j] denote whether a substring from i to j is palindrome.

Changing condition:

table[i+1][j-1] == 1 && s.charAt(i) == s.charAt(j)
=>
table[i][j] == 1

Time O(n^2) Space O(n^2)

public String longestPalindrome(String s) {
    if(s==null || s.length()<=1)
        return s;
 
    int len = s.length();
    int maxLen = 1;
    boolean [][] dp = new boolean[len][len];
 
    String longest = null;
    for(int l=0; l<s.length(); l++){
        for(int i=0; i<len-l; i++){
            int j = i+l;
            if(s.charAt(i)==s.charAt(j) && (j-i<=2||dp[i+1][j-1])){
                dp[i][j]=true;
 
                if(j-i+1>maxLen){
                   maxLen = j-i+1; 
                   longest = s.substring(i, j+1);
                }
            }
        }
    }
 
    return longest;
}

For example, if the input string is "dabcba", the final matrix would be the following:

1 0 0 0 0 0 
0 1 0 0 0 1 
0 0 1 0 1 0 
0 0 0 1 0 0 
0 0 0 0 1 0 
0 0 0 0 0 1 

From the table, we can clearly see that the longest string is in cell table[1][5].

2. A Simple Algorithm

Time O(n^2), Space O(1)

public String longestPalindrome(String s) {
	if (s.isEmpty()) {
		return null;
	}
 
	if (s.length() == 1) {
		return s;
	}
 
	String longest = s.substring(0, 1);
	for (int i = 0; i < s.length(); i++) {
		// get longest palindrome with center of i
		String tmp = helper(s, i, i);
		if (tmp.length() > longest.length()) {
			longest = tmp;
		}
 
		// get longest palindrome with center of i, i+1
		tmp = helper(s, i, i + 1);
		if (tmp.length() > longest.length()) {
			longest = tmp;
		}
	}
 
	return longest;
}
 
// Given a center, either one letter or two letter, 
// Find longest palindrome
public String helper(String s, int begin, int end) {
	while (begin >= 0 && end <= s.length() - 1 && s.charAt(begin) == s.charAt(end)) {
		begin--;
		end++;
	}
	return s.substring(begin + 1, end);
}

3. Manacher's Algorithm

Manacher's algorithm is much more complicated to figure out, even though it will bring benefit of time complexity of O(n). Since it is not typical, there is no need to waste time on that.

Category >> Algorithms  
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code> 
String foo = "bar";
</code></pre>
  • wu

    in scala

    “`
    def findPS(os: String) = {
    def isPS(s: String): Boolean = s == s.reverse
    val idxedS = os.toList.zip(0 until os.length)
    val idxDict = idxedS
    .groupBy[Char]{ case (c, idx) => c }
    .map {case (c, tps) => (c, tps.map(_._2).sorted.reverse)}
    var (psLength, psStr) = (1, “”)
    idxedS.foreach { case (c, idx) =>
    idxDict(c).takeWhile(_ > idx).foreach { nIdx =>
    os.substring(idx, nIdx + 1) match {
    case subS if isPS(subS) && nIdx-idx > psLength =>
    psLength = nIdx – idx + 1
    psStr = subS
    case _ => ()
    }
    }
    }
    psStr
    }
    “`

  • Lakshminarayan Kamath

    public class LongestPalindrome
    {
    public static void main(String[] args)
    {
    String input=”abccbp”;
    String longest=longestPalindrome(input);
    System.out.println(longest);
    }

    public static String longestPalindrome(String input)
    {
    if(input.isEmpty())
    return input;

    if(input.length()==1)
    return input;

    String longest=””;
    String output=””;
    int length=0;

    for(int i=0;i<input.length();i++)
    {
    longest="";

    for(int j=i;jlength)
    {
    length=longest.length();
    output=longest;
    }
    }
    }
    }

    return output;
    }
    }

  • CRH

    I think Solution 3 expects the characters to be adjacent. This question usually is just about finding longest NOT necessarily contiguous substring. The recursive approach of this problem will be exponential time, 2^n . But using dynamic programming time can be reduced to n^2

  • 卢刘杰

    yep ! u are right. the objective is to make the length between i and j is 3.

  • 卢刘杰

    I suppose u at wrong at some point.

  • Harish

    ABCCBP iis working fine. But incase I give ABCDA, the longest possible palindrome is ‘AA’ but it is showing ‘A’. Hope I didn’t unnderstand it wrong..!

  • NotActually An FormulaFan

    I did this in pseudo code since I am novice at Java
    test: “satdoggodabca”
    –main:
    —-loop (idx=0;idx<length;idx++):
    ——get char (baseChar) at idx
    ——loop:
    ——–find char again in test (testChar)
    ——–test if testChar– matches baseChar++, loop until indexes are equal, store if equal

    visual representation:

    1. satdoggodabca

    2. s_____________ (no other 's' found) t: length

    3. _a________a__a (test if inner characters of found 'a' match the next character of the other 'a') t:length – 1

    3. _at______da_ca ( no matches here, continue) t: # of found chars

    4. __t___________ ( none for 't') t: length – 3

    5. ___d_____d___ ( test 'd') t: length – 4

    5. ___do__od___ ( looking good) t: # of found chars

    5. ___doggod___ (yeeee, also note since it is left most and we started by whole string scanning, we can assume this is the longest palindrome)

    estimated worst time: O(n * (n-k))

  • Youchen

    The DP solution above did not pass the test case which is the “aaa…aabcaa…aaa”, its length is 1,000 and the ‘b’ is in index 498. OJ shows that “Time Limit Exceeded”.

  • Salil Surendran

    What do you guys think of this solution. This is an O(n) solution

    private String findLongestPalindromicSubString(String str){

    if(str == null || str.length() == 0)
    return null;
    else if(str.length() == 1)
    return str;
    else{
    //Traverse down the string and which is each character
    //check this logic.
    int index=1;
    String longestPalindrome=null;
    while(index < str.length()/*||
    (longestPalindrome != null && str.length() – index 2 && str.charAt(index) == str.charAt(index – 2))
    currentPalindrome=readPalindrome(index – 2, index, str);

    if(currentPalindrome != null){
    if(longestPalindrome == null || currentPalindrome.length() > longestPalindrome.length())
    longestPalindrome=currentPalindrome;
    index+=currentPalindrome.length() / 2;
    }else
    index++;
    }
    return longestPalindrome;
    }
    }

  • YouYouMe

    The bounds checking of the helper function is wrong. Why does the helper func return the substring from begin + 1? and what if the while loop breaks at end = s.length?

    If the loop breaks before begin < 0 and before end = s.length it should just return substr(begin, end).

    so somethin like:

    if (begin s.length – 1) end = s.length -1;

    return s.substring(begin, end);

  • Sweta Shah

    Hello,

    Can someone let me know what is the time and space complexity for my solution to this problem below?


    public static String longestPalindrome(String[] stringArray) {
    if (stringArray.length == 1) {
    return stringArray[0];
    }
    if (stringArray.length == 0) {
    return null;
    }
    int maxLength = 0;
    String longestPal = "";
    for (final String eachString : stringArray) {
    if (isPalindrome(eachString) && eachString.length() > maxLength) {
    maxLength = eachString.length();
    longestPal = eachString;
    }
    }
    return longestPal;
    }

    public static boolean isPalindrome(String testStr) {
    int i = 0, j = testStr.length() - 1;
    while (i != j) {
    if (testStr.charAt(i) == testStr.charAt(j)) {
    i++;
    j--;
    } else {
    return false;
    }
    }
    return true;
    }

  • Guest


    public static void main(){

    }

  • Guest

    Hello,

    Can someone let me know what would be the time and space complexity of my solution here?

    public static String longestPalindrome(String[] stringArray) {

    if (stringArray.length == 1) {

    return stringArray[0];

    }

    if (stringArray.length == 0) {

    return null;

    }

    int maxLength = 0;

    String longestPal = “”;

    for (final String eachString : stringArray) {

    if (isPalindrome(eachString) && eachString.length() > maxLength) {

    maxLength = eachString.length();

    longestPal = eachString;

    }

    }

    return longestPal;

    }

    public static boolean isPalindrome(String testStr) {

    int i = 0, j = testStr.length() – 1;

    while (i != j) {

    if (testStr.charAt(i) == testStr.charAt(j)) {

    i++;

    j–;

    } else {

    return false;

    }

    }

    return true;

    }

  • JY

    In addition, the outer loop should be. Not necessary, but makes more sense.
    for (int i = 0; i < length-1; i++)

  • JY

    I think Kishore is talking about solution 1, public static boolean isPalindrome(String s);. Since this method is checking whether the passed string instance is a palindrome or not, you only need to iterate half of its length; otherwise, we are checking the same value twice if the string is palindrome.

  • heena

    For more programs Refer http://javatutorialhere.blogspot.in/

  • ramesh

    to reduce the number of iterations in the first case

    public static boolean isPalindrome(String s) {
    int j = (s.length()%2)!=0?(s.length()/2):((s.length()/2)+1);
    int i=0;
    for (i = 0; i < j; i++) {
    if (s.charAt(i) != s.charAt((s.length() – 1) – i)) {
    return false;
    }
    }
    return true;
    }

  • drake

    @Pankaj: Did you run the program? I executed with ABCCP as input string the output was BCCB

  • ryanlr

    You may want to run the code again. I used “ABCCBP” to test, and it worked.

  • Pankaj

    This would not work correctly, ex. ABCCBP. It wont be able to find exact longest palindrom which is BCCB

  • Learner

    Can anyone help me finding the complexity of this? ->
    private static boolean checkPaliSubstring(String str1) {
    boolean paliSubstr = false;
    int longestlen = 0;

    String sub1 = str1.substring(1);
    if(checkPalindrome(sub1) && sub1.length()>longestlen){
    longestSubPalindrome= sub1;//class field
    longestlen = sub1.length();
    paliSubstr = true;
    }

    String sub2 = str1.substring(0, str1.length()-1);
    if(checkPalindrome(sub2) && sub2.length()>longestlen){
    longestSubPalindrome= sub2;//class field
    longestlen = sub2.length();
    paliSubstr = true;
    }

    if(!paliSubstr && sub1.length()!=2){
    checkPaliSubstring(sub1);
    }

    if(!paliSubstr && sub2.length()!=2){
    checkPaliSubstring(sub2);
    }

    return paliSubstr;//substring palindrome exists or not
    }

  • Codethecode

    Can we put indices of all occurrences of chars in a hash table and then pursue just ones with count >2 ? Could be simpler IMO

  • thundear

    table[i][i] and table[i][i+1] is calculated in the first two for loop.
    l=3 to start the third for loop is to solve the condition that table[i][j] where the gap between i and j is above 2.

  • Mallikarjun

    Sorry. Wrong Optimization. Found a scenario where it can fail. Your one is the correct one.

  • Mallikarjun

    I feel, can be slightly optimized of we jump to end of the present max. something like this. Observe for j. (Let me know whether it is correct or can miss some scenarios).

    int j=0;
    String longest = s.substring(0, 1);
    for (int i = 0; i longest.length()) {
    longest = tmp;
    j = tmp.length()/2;
    }

    // get longest palindrome with center of i, i+1
    tmp = helper(s, i, i + 1);
    if (tmp.length() > longest.length()) {
    longest = tmp;
    j = tmp.length()/2;
    }

  • Mallikarjun

    There could be the palindrome in the second half. It always need not be the spread around the center.

  • Faris

    How can i find the longest str by using the final matrix?

  • Kishore

    In the isPalindrome method, the checking can only be done till

    i < s.length()/2

  • Yash

    In the DP solution why is the l in the first for loop set to 3?

  • ryanlr

    Good Algorithm.

  • Yifan

    My solution: Time O(n^2) Space O(1)

    public String longestPalindrome(String s) {
    if (s.isEmpty()) {
    return null;
    }

    if (s.length() == 1) {
    return s;
    }

    String longest = s.substring(0, 1);
    for (int i = 0; i longest.length()) {
    longest = tmp;
    }

    // test s[i,i+1]
    tmp = helper(s, i, i + 1);
    if (tmp.length() > longest.length()) {
    longest = tmp;
    }
    }
    return longest;
    }

    // [begin, end]
    public String helper(String s, int begin, int end) {
    while (begin >= 0
    && end <= s.length() – 1
    && s.charAt(begin) == s.charAt(end)) {
    begin–;
    end++;
    }
    return s.substring(begin + 1, end);
    }