5. Longest Palindromic Substring
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Key Point
Solution 1: Expand Around Center.
Time complexity: O(n^2), space complexity: O(1)
class Solution {
public String longestPalindrome(String s) {
if(s == null || s.length()<=1)
return s;
int start = 0;
int end = 0;
for(int i = 0; i < s.length(); i++) {
int left = i;
int right = i;
while(left!=-1 && right!=s.length() && s.charAt(left)==s.charAt(right)) {
left--;
right++;
}
if((right-left) > (end-start)) {
start = left;
end = right;
}
left = i;
right = i+1;
while(left!=-1 && right!=s.length() && s.charAt(left)==s.charAt(right)) {
left--;
right++;
}
if((right-left) > (end-start)) {
start = left;
end = right;
}
}
return s.substring(start+1,end);
}
}
Solution 2: Brute Force, time complexity: O(n^3), space complexity: O(1)
Ignored Cases
class Solution {
public String longestPalindrome(String s) {
if(s == null || s.equals(""))
return s;
int start = 0;
int end = 0;
for(int i = 0; i < s.length(); i++)
//j should be not less than i
for(int j = s.length()-1; j >= i; j--) {
if( isPalindrome(s,i,j)&&(j-i) >(end-start)) {
start = i;
end = j;
}
}
return s.substring(start,end+1);
}
public boolean isPalindrome(String s, int start, int end) {
if(start >= end)
return true;
if(s.charAt(start) != s.charAt(end))
return false;
return isPalindrome(s, start+1, end-1);
}
}
Solution 3: Brute Force, but start from the longest search length, so once found, immediately return the result
Time Complexity: O(n^3), Space Complexity: O(1)
class Solution {
public String longestPalindrome(String s) {
if(s == null || s.equals(""))
return s;
for(int len = s.length(); len > 0; len--) {
for(int i = 0; i <= s.length()-len; i++) {
if( isPalindrome(s,i,i+len-1))
return s.substring(i,i+len);
}
}
return null;
}
public boolean isPalindrome(String s, int start, int end) {
if(start >= end)
return true;
if(s.charAt(start) != s.charAt(end))
return false;
return isPalindrome(s, start+1, end-1);
}
}
Solution 4: Dynamic Programming, we can compare each pair of characters and store them in a 2D array.
Time Complexity: O(n^2). Space Complexity: O(n^2)
Consideration:
class Solution {
public String longestPalindrome(String s) {
if(s == null || s.length()<=1)
return s;
int len = s.length();
int maxLen = 1;
int maxStart = 0;
boolean[][] d = new boolean[len][len];
for(int i = 0; i < len; i++) {
d[i][i] = true;
}
char[] chars = s.toCharArray();
for(int i = 0; i < len-1; i++) {
if(chars[i] == chars[i+1]) {
d[i][i+1] = true;
if(maxLen < 2) {
maxLen = 2;
maxStart = i;
}
} else {
d[i][i+1] = false;
}
}
for(int j = 2; j < len; j++) {
// i should be less than j-1, since the condition for d[i][i+1] has been considered previously
for(int i = 0; i < j-1; i++) {
d[i][j] = (chars[i]==chars[j] && d[i+1][j-1]);
if(d[i][j] && j-i+1 > maxLen) {
maxLen = j-i+1;
maxStart = i;
}
}
}
return s.substring(maxStart, maxStart+maxLen);
}
}
Solution 5: Manacher’s algorithm
Time Complexity: O(n), Space Complexity: O(n)
References: https://www.cnblogs.com/bitzhuwei/p/Longest-Palindromic-Substring-Part-II.html
class Solution {
public String longestPalindrome(String s) {
if(s==null || s.length() <=1) {
return s;
}
String T = preProcess(s);
int R = 0;
int C = 0;
int len = T.length();
int[] P = new int[len];
for(int i = 1; i < len-1; i++) {
int i_mirror = C-(i-C);
int diff = R-i;
if(diff < 0) {// i is out the range of [L,R]
//recalculate the palindrome length
P[i] = 0;
while(T.charAt(i-P[i]-1) == T.charAt(i+P[i]+1))
P[i]++;
C = i;
R = i+P[i]-1;
} else {
if(P[i_mirror] <= diff) {//the palindrome length centered at i_mirror is less than the maximal palindrome length centered at C
P[i] = P[i_mirror];
} else {
P[i] = diff;
while(T.charAt(i-P[i]-1) == T.charAt(i+P[i]+1))
P[i]++;
C = i;
R = i+P[i]-1;
}
}
}
int maxLen = 0;
int maxCen = 0;
for(int i = 1; i < len-1; i++) {
if(P[i] > maxLen) {
maxLen = P[i];
maxCen = i;
}
}
return s.substring((maxCen-1-maxLen)/2, (maxCen-1-maxLen)/2+maxLen);
}
public String preProcess(String s) {
String T = "^";
for(int i = 0; i < s.length(); i++)
T+="#"+s.charAt(i);
T += "#$";
return T;
}
}
== Solution 6: Longest Common Substring==
Time Complexity: O(n^2), Space Complexity:O(n^2)
Considerations
class Solution {
public String longestPalindrome(String s) {
if(s == null || s.length()<=1)
return s;
String revS = new StringBuilder(s).reverse().toString();
int len = s.length();
int[][] arr = new int[len][len];
int maxLen = 0;
int maxEnd = 0;
for(int i = 0; i < len; i++) {
for(int j = 0; j < len; j++) {
if(revS.charAt(j) == s.charAt(i)) {
if(i==0||j==0)
arr[i][j] = 1;
else
arr[i][j] = arr[i-1][j-1]+1;
} else {
arr[i][j] = 0;
}
// both i and j point to the end of the array
// we should find whether the end index of the substring in revS equals to i
int beforeRev = len-1-j;
if(i==beforeRev+arr[i][j]-1) {
if(arr[i][j] > maxLen) {
maxLen = arr[i][j];
maxEnd = i;
}
}
}
}
return s.substring(maxEnd+1-maxLen,maxEnd+1);
}
}
== Solution 7: Longest Common Substring (improved space complexity)==
Time Complexity: O(n^2), Space Complexity:O(n)
Considerations
class Solution {
public String longestPalindrome(String s) {
if(s == null || s.length()<=1)
return s;
String revS = new StringBuilder(s).reverse().toString();
int len = s.length();
int[] arr = new int[len];
int maxLen = 0;
int maxEnd = 0;
for(int i = 0; i < len; i++) {
for(int j = len-1; j >= 0; j--) {
if(revS.charAt(j) == s.charAt(i)) {
if(i==0||j==0)
arr[j] = 1;
else
arr[j] = arr[j-1]+1;
} else {
arr[j] = 0;
}
// both i and j point to the end of the array
// we should find whether the end index of the substring in revS equals to i
int beforeRev = len-1-j;
if(i==beforeRev+arr[j]-1) {
if(arr[j] > maxLen) {
maxLen = arr[j];
maxEnd = i;
}
}
}
}
return s.substring(maxEnd+1-maxLen,maxEnd+1);
}
}
== References==