回文字符串 (palindrome)
Find the longest substring in the string
- Force way
区分奇偶回文字符串
找最长奇数回文字符串需逐个从单个字符串向两边扩展
找最长偶数回文字符串需逐个从两个字符串中间向两边扩展
代码实现 O(n^2)
public class Main {
public static int expend (int left , int right , String s ){
int l = left;
int r = right;
int res = 0 ;
while(l>=0&&r<s.length()&&s.charAt(l)==s.charAt(r)){
res = r- l + 1;
l--;
r++;
}
return res;
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
String str = cin.next();
int ans = 0;
for(int i = 0 ;i <str.length();i++){
int max1 = expend(i,i,str); //奇数
int max2 = expend(i,i+1,str); //偶数
int res = Math.max(max1,max2); //比较最大值
ans = Math.max(ans,res); //结果最大值
}
System.out.println(ans);
}
}
- Manacher
在字符串首尾和字符间添加相同任意字符,使字符串中的回文字符串一直为奇数字符串
如 abba -> #a#b#b#a# abcbd -> #a#b#c#b#d#
使用数组来记录以每个字符为回文中心的回文半径
使用R来记录当前最大回文串的最右坐标的下位
使用C来记录当前最大回文串的中心坐标
分当前查找字符在R内部和在R外部来讨论
代码实现 O(n)
public class Main {
static String toManacher(String s){
StringBuilder str = new StringBuilder();
str.append("#");
for(int i = 0 ; i < s.length(); i++){
str.append(s.charAt(i));
str.append("#");
}
return str.toString();
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
String s = cin.next();
s = toManacher(s); //添加#号
int R = -1; // 当前最右回文边界下一位
int C = -1; // 当前最长回文中心
int Max= Integer.MIN_VALUE;
int[] parr = new int[s.length()];//记录回文半径
for(int i = 0 ; i < s.length() ;i++){
parr[i] = R > i ? Math.min(parr[2*C-i],R-i) : 1;
while((i-parr[i]>=0) && (i+parr[i] < s.length())) {
if (s.charAt(i - parr[i]) == s.charAt(i + parr[i])) {
parr[i]++;
} else {
break;
}
}
if(i+parr[i] > R){
R = i+parr[i]; //更新最右边界
C = i;//更新中心位置
}
Max = Math.max(parr[i]-1,Max);
}
System.out.println(Max);
}
}