文字列sを指定すると、文字列の前に文字を追加して回文に変換できます。この方法で変換できる最短のパリンドロームを見つけて返します。
例1:
入力: "aacecaaa"
出力: "aaacecaaa"
解決策:文字列の接頭辞パリンドローム文字列を見つけ、残りの文字列を逆にして文字列のフロントエンドに追加します。manacherアルゴリズムを使用して、文字列の接頭辞パリンドローム文字列を見つけることができます。
class Solution {
public String shortestPalindrome(String s) {
int palindrome=0;
StringBuffer S=new StringBuffer();
/*
* 填充字符串,在两个字符串的中间和两端填充‘#’,使得字符串的长度为奇数
* 在字符串新的两端填充‘$’、‘!’、防止越界问题
* 遍历新字符串,以新字符串的每个字符为中心,向外扩展,记录回文字符串的最大半径
* 回文字符串的长度:回文字符串半径-1
*/
for(int i=0;i<s.length();i++){
if(i==0)
S.append("!");
S.append("#"+s.charAt(i));
}
S.append("#$");
/*
* 我们用int[]r保存s中以每个字符为中心的最大回文字符串半径
* manacher算法中,我们要维护一个当前的最大回文半径rMax,和这个最大回文半径
* 所对应的回文中心center,以及最大边界(right=center+rMax-1),如果当前的字符串中心k在
* 最大边界内(k<edge),则Math.min(r[2*center-i],right-i)一定在k的回文字符串半径范围内,
* 可以设此为向外扩展的初始值,以减少程序运行次数(利用已知回文字符串优化程序运行)
*/
int rMax=1;
int center=0;
int right=0;
int[]r=new int[S.length()];
for(int i=1;i<S.length()-1;i++){
if(i<=right)
r[i]=Math.min(r[2*center-i],right-i+1);
else
r[i]=1;
while(S.charAt(i-r[i])==S.charAt(i+r[i])){
r[i]++;
}
if(r[i]>rMax||i>right){
center=i;
rMax=r[i];
right=rMax+center-1;
}
//如果r[i]==i,则说明是前缀回文字符串
if(r[i]==i)
palindrome=r[i]-1;
}
String add=palindrome==s.length()?"":s.substring(palindrome);
return new String(new StringBuffer(add).reverse().toString()+s);
}
}