给一个字符串 S, 你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
例如:
给出 “aacecaaa”,返回 “aaacecaaa”。
给出 “abcd”,返回 “dcbabcd”。
因为只能在串首添加字符串,解题的思路比较好想:
令res = s.reverse,找到res的最大后缀suffix,其中suffix=s的前缀prefix,那么答案就是
s.reverse-suffix+s
public String shortestPalindrome(String s) {
if(s.length() < 1){
return s;
}
int len = s.length();
String res = new StringBuilder(s).reverse().toString();
for(int i=0;i<len;i++){
if(res.substring(i,len).equals(s.substring(0,len-i))){
return new StringBuilder(res).append(s.substring(len-i,len)).toString();
}
}
return new StringBuilder(res).append(s.substring(0,len)).toString();
}
但是 testcase有一个很长的全a字符串,以上解法会超时,要通过此case,还是要通过kmp算法快速找到res的最大后缀suffix,然后求得解,kmp算法实现看:这里
private void getLPS(String s, int[] lps){
// i是后缀末尾的指针,j是前缀末尾的指针
int j = 0, i = 1;
lps[0] = 0;
// 从j=0,i=1开始找,错开了一位
while(i < s.length()){
// 如果字母相等,则继续匹配,最长相同前后缀的长度也加1
if(s.charAt(i) == s.charAt(j)){
lps[i] = j + 1;
i++;
j++;
// 如果不同
} else {
// 如果前缀末尾指针还没退回0点,则找上一个子前缀的末尾位置
if(j != 0){
j = lps[j - 1];
// 如果退回0点,则最长相同前后缀的长度就是0了
} else {
lps[i] = 0;
i++;
}
}
}
}
public String shortestPalindrome(String s) {
if(s.length() < 1){
return s;
}
int len = s.length();
String rev = new StringBuilder(s).reverse().toString();
int next[] = new int[len*2+1];
getLPS( new StringBuilder(s).append("#").append(rev).toString(), next);
return new StringBuilder(rev.substring(0,len-next[next.length-1])).append(s).toString();
}