最长回文子串
题目描述
给定一个字符串 SS,请你求出 SS 的最长回文子串。
输入描述
输入仅一行,包含一个字符串 SS。
1≤∣S∣≤5×1051≤∣S∣≤5×105,保证 SS 只包含小写字母、大写字母、数字。
输出描述
输出共 11 行,包含一个整数,表示答案。
输入输出样例
示例 1
输入
aa1ABA1b
输出
5
运行限制
- 最大运行时间:2s
- 最大运行内存: 256M
暴搜(超时)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int N = 2*100010,p=131,mod=(int)(1e9)+7;//改值减少冲突
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// int n=Integer.parseInt(br.readLine());
// String g[] = br.readLine().split(" ");
// int n=Integer.parseInt(g[0]),q=Integer.parseInt(g[1]);
String string=br.readLine();
int res=1;
//以一个字符为回文串的中心
for (int i = 1; i < string.length()-1; i++) {
//二分回文半径的大小 小的是回文 大的一定是回文 有单调性 可用二分
int left=0;
int right=Math.min(i-left, string.length()-1-i);
while(left<right){
int mid=(left+right+1)>>1;
int l=i-mid,r=i+mid;
if(string.substring(l,i).equals(new StringBuilder(string.substring(i + 1, r + 1)).reverse().toString())){
left=mid;
}else{
right=mid-1;
}
}
res=Math.max(res, 2*left+1);
}
//以二个字符为回文串的中心
for (int i = 1; i < string.length()-1; i++) {
//二分回文半径的大小 小的是回文 大的一定是回文 有单调性 可用二分
int left=0;
int right=Math.min(i-left, string.length()-1-i-1);
while(left<right){
int mid=(left+right+1)>>1;
int l=i-mid,r=i+1+mid;
if(string.substring(l,i).
equals(new StringBuilder(string.substring(i+2, r+1)).reverse().toString())){
left=mid;
}else{
right=mid-1;
}
}
res=Math.max(res, 2*left+2);
}
System.out.println(res);
}
}
哈希优化
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int N = 5*100010,p=131,mod=(int)(1e9)+7;//改值减少冲突
static long a[]=new long[N];
static long b[]=new long[N];
static long ra[]=new long[N];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// int n=Integer.parseInt(br.readLine());
// String g[] = br.readLine().split(" ");
// int n=Integer.parseInt(g[0]),q=Integer.parseInt(g[1]);
String string=" "+br.readLine();
int res=1;
b[0]=1;
for (int i = 1; i <=string.length()-1; i++) {
b[i]=b[i-1]*p%mod;
a[i]=(a[i-1]*p+string.charAt(i))%mod;
}
ra[string.length()]=0;
for (int i =string.length()-1; i>0; i--) {
ra[i]=(ra[i+1]*p+string.charAt(i))%mod;
}
//以一个字符为回文串的中心
for (int i = 2; i < string.length()-1; i++) {
//二分回文半径的大小 小的是回文 大的一定是回文 有单调性 可用二分
int left=0;
int right=Math.min(i-1, string.length()-1-i);
while(left<right){
int mid=(left+right+1)>>1;
int l=i-mid,r=i+mid;
if(getHash(l,i-1)==getRevHash(i + 1, r)){
left=mid;
}else{
right=mid-1;
}
}
res=Math.max(res, 2*left+1);
}
//以二个字符为回文串的中心
for (int i = 2; i < string.length()-1; i++) {
if(string.charAt(i) !=string.charAt(i+1))continue;
//二分回文半径的大小 小的是回文 大的一定是回文 有单调性 可用二分
int left=0;
int right=Math.min(i-1, string.length()-1-i-1);
while(left<right){
int mid=(left+right+1)>>1;
int l=i-mid,r=i+1+mid;
if(getHash(l,i-1)==getRevHash(i+2, r)){
left=mid;
}else{
right=mid-1;
}
}
res=Math.max(res, 2*left+2);
}
System.out.println(res);
}
static int getHash(int l,int r){
return (int)((a[r]-a[l-1]*b[r-l+1])%mod+mod)%mod;
}
static int getRevHash(int l,int r){
return (int)((ra[l]-ra[r+1]*b[r-l+1])%mod+mod)%mod;
}
}