Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.
For example:
Given "aacecaaa"
, return "aaacecaaa"
.
Given "abcd"
, return "dcbabcd"
.
Solution:
First reverse the string abcd -> dcba
then compare two strings find the longest substring that is the prefix of s and the suffix of s.reverse()
Shift to match and add together
abcd
+ dcba
---------------
dcbabcd
Code:
public class Solution {
public String shortestPalindrome(String s) {
String rev = new StringBuilder(s).reverse().toString();
for(int i = 0 ; i < s.length(); i++){
if(rev.substring(i).equals(s.substring(0,s.length() - i))){
return rev.substring(0,i) + s;
}
}
return rev + s;
}
}
This will get TLE since it took O(n2) to find the common prefix/suffix.
Using KMP to find the prefix suffix is much faster, taking O(n) time
First we build the string s + "#" + s.reverse().
a b c d # d c b a
and the kmp table should be:
a b c d # d c b a
0 0 0 0 0 0 0 0 1
return dcbabcd
the number in the table means the length of the common prefix/suffix ends at that position
Another example
a a c e c a a a # a a a c e c a a
0 1 0 0 0 1 2 2 0 1 2 2 3 4 5 6 7
so the anwser is a + a a c e c a a a = aaacecaaa
How to compute this table?
public int[] computeKMP(String p){
int[] ret = new int[p.length()];
int j = 0;
int i = 1;
while(i < p.length()){
if(p.charAt(j) == p.charAt(i)){
ret[i] = j + 1;
j++;
i++;
} else {
if(j == 0){
ret[i] = 0;
i++;
} else{
j = ret[j - 1];
}
}
}
return ret;
}
And the code:
public String shortestPalindrome(String s) {
String rev = new StringBuilder(s).reverse().toString();
String p = s + "#" + rev;
int[] kmp = computeKMP(p);
int len = kmp[kmp.length - 1];
return new StringBuilder(s.substring(len)).reverse().toString() + s;
}