package com.interview.string; /** * Date 07/29/2015 * @author Tushar Roy * * Given a string find longest palindromic substring in this string. * * References * http://www.geeksforgeeks.org/longest-palindrome-substring-set-1/ * http://www.geeksforgeeks.org/longest-palindromic-substring-set-2/ * http://articles.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html * http://www.akalin.cx/longest-palindrome-linear-time * http://tarokuriyama.com/projects/palindrome2.php */ public class LongestPalindromeSubstring { public int longestPalindromeSubstringEasy(char arr[]) { int longest_substring = 1; for (int i = 0; i < arr.length; i++) { int x, y; int palindrome; x = i; y = i + 1; palindrome = 0; while (x >= 0 && y < arr.length && arr[x] == arr[y]) { x--; y++; palindrome += 2; } longest_substring = Math.max(longest_substring, palindrome); x = i - 1; y = i + 1; palindrome = 1; while (x >= 0 && y < arr.length && arr[x] == arr[y]) { x--; y++; palindrome += 2; } longest_substring = Math.max(longest_substring, palindrome); } return longest_substring; } /** * Linear time Manacher's algorithm to find longest palindromic substring. * There are 4 cases to handle * Case 1 : Right side palindrome is totally contained under current palindrome. In this case do not consider this as center. * Case 2 : Current palindrome is proper suffix of input. Terminate the loop in this case. No better palindrom will be found on right. * Case 3 : Right side palindrome is proper suffix and its corresponding left side palindrome is proper prefix of current palindrome. Make largest such point as * next center. * Case 4 : Right side palindrome is proper suffix but its left corresponding palindrome is be beyond current palindrome. Do not consider this * as center because it will not extend at all. * * To handle even size palindromes replace input string with one containing $ between every input character and in start and end. */ public int longestPalindromicSubstringLinear(char input[]) { int index = 0; //preprocess the input to convert it into type abc -> $a$b$c$ to handle even length case. //Total size will be 2*n + 1 of this new array. char newInput[] = new char[2*input.length + 1]; for(int i=0; i < newInput.length; i++) { if(i % 2 != 0) { newInput[i] = input[index++]; } else { newInput[i] = '$'; } } //create temporary array for holding largest palindrome at every point. There are 2*n + 1 such points. int T[] = new int[newInput.length]; int start = 0; int end = 0; //here i is the center. for(int i=0; i < newInput.length; ) { //expand around i. See how far we can go. while(start >0 && end < newInput.length-1 && newInput[start-1] == newInput[end+1]) { start--; end++; } //set the longest value of palindrome around center i at T[i] T[i] = end - start + 1; //this is case 2. Current palindrome is proper suffix of input. No need to proceed. Just break out of loop. if(end == T.length -1) { break; } //Mark newCenter to be either end or end + 1 depending on if we dealing with even or old number input. int newCenter = end + (i%2 ==0 ? 1 : 0); for(int j = i + 1; j <= end; j++) { //i - (j - i) is left mirror. Its possible left mirror might go beyond current center palindrome. So take minimum //of either left side palindrome or distance of j to end. T[j] = Math.min(T[i - (j - i)], 2 * (end - j) + 1); //Only proceed if we get case 3. This check is to make sure we do not pick j as new center for case 1 or case 4 //As soon as we find a center lets break out of this inner while loop. if(j + T[i - (j - i)]/2 == end) { newCenter = j; break; } } //make i as newCenter. Set right and left to atleast the value we already know should be matching based of left side palindrome. i = newCenter; end = i + T[i]/2; start = i - T[i]/2; } //find the max palindrome in T and return it. int max = Integer.MIN_VALUE; for(int i = 0; i < T.length; i++) { int val; /* if(i%2 == 0) { val = (T[i] -1)/2; } else { val = T[i]/2; }*/ val = T[i]/2; if(max < val) { max = val; } } return max; } public int longestPalindromeDynamic(char []str){ boolean T[][] = new boolean[str.length][str.length]; for(int i=0; i < T.length; i++){ T[i][i] = true; } int max = 1; for(int l = 2; l <= str.length; l++){ int len = 0; for(int i=0; i < str.length-l+1; i++){ int j = i + l-1; len = 0; if(l == 2){ if(str[i] == str[j]){ T[i][j] = true; len = 2; } }else{ if(str[i] == str[j] && T[i+1][j-1]){ T[i][j] = true; len = j -i + 1; } } if(len > max){ max = len; } } } return max; } public static void main(String args[]) { LongestPalindromeSubstring lps = new LongestPalindromeSubstring(); System.out.println(lps.longestPalindromicSubstringLinear("abba".toCharArray())); System.out.println(lps.longestPalindromicSubstringLinear("abbababba".toCharArray())); System.out.println(lps.longestPalindromicSubstringLinear("babcbaabcbaccba".toCharArray())); System.out.println(lps.longestPalindromicSubstringLinear("cdbabcbabdab".toCharArray())); } }