字符串hash系列之最长回文子串

139. 回文子串的最大长度 - AcWing题库

这个题我使用官方的给的做法,nlogn的时间复杂度,结果Java没过,最后一个样例tle了,即使我用了快读与快输也无济于事,换成c加加就过了,怀疑这个题数据卡的及其严格。差评,差评。实测后,发现有人使用Java运用Manacher算法过了,博主还不会。

流汗流汗,现在挖个坑,先使用字符串hash来解决问题,以后学会了Manacher再来填坑。

言归正传,此题我们要求最大回文子串,我们知道枚举的话至少时n的平方的复杂度,肯定不行。于是我们来优化优化,首先我们可以使用字符串hash来极大降低我们判断回文串的时间。具体做法是,我们首先来枚举最长回文子串的中心位置。我们知道回文子串分为奇数回文子串和偶数回文子串。我们枚举奇数回文子串的中心字符,对于偶数回文子串我们枚举最中心的两个字符里靠后的那一个,当然枚举最中心的两个字符里靠前的那一个也可以。然后,我们来二分答案。怎么来二分呢。我们在预先处理完字符串的hash后,我们将1视为第一个字符的位置。我们以奇数子串为例。我们的循环从1开始,直到n。假设当前位置为m。我们从m-1与n-m这两个数字中选取最小值作为我们针对m位置二分的右端点。左端点设为0.我们知道奇数回文子串,他的中心字符前面有m-1个字符,后面有n-m个字符,既然回文,当然中心字符前面的字符数量要等于后面的,所以我们要选取最小的。接下来二分。我们针对m位置二分mid,mid就是中心字符除外的中心字符往左的所有字符长度,所以左边是m-1到m-mid,右边同理m+1到m+mid。我们对这两个位置的字符求hash值来比较二分出答案后,我们乘以2加1就是选出最长就是奇数答案

针对偶数回文子串。我们从m-1到n-m+1中取得最小值来作为我们二分的右端点,左端点选为0.

同奇数子串的步骤我们在m-mid到m-1和m到m+mid-1来求解。得到二分答案后乘以2,在所有答案中选取最长的,同奇数子串做对比,取最大的作为答案。

再求字符串hash时,我们可以再开一个后缀和,来判断右边字符串的hash值。

上代码


import java.awt.FontFormatException;
import java.io.BufferedReader; 
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.AnnotatedWildcardType;
import java.math.BigInteger;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.Spliterator.OfPrimitive;
import java.util.function.IntToDoubleFunction;
import java.util.function.LongBinaryOperator;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.management.relation.InvalidRelationTypeException;
import javax.print.attribute.standard.JobMessageFromOperator;
import javax.print.attribute.standard.JobPriority;
import javax.swing.table.TableModel;
import javax.swing.text.TabSet;
public class Main {
  public static void main(String[] args) throws IOException  {
Scanner sc=new Scanner(System.in);
BufferedReader br1=new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw1=new PrintWriter(System.out);
yuchuyi();
int a=0;
while(true) {
	a++;
	String a1=br1.readLine();
	long answwer=0;
	if(a1.equals("END")) {
		break;
	}
	hashchuli(a1);
	hash2chuli(a1);
	int b=0;
	int c=a1.length();
	for(b=1;b<=c;b++) {
		int d=0;
		int e=Math.min(b-1, c-b);
		int f=0;
		while(d<=e) {
			int mid=(d+e)>>>1;	
	         long a2=jisuanhash(b-mid,b-1);
	         long b2=jisuanhash2(b+1, b+mid);
	        /* if(b==7) {
	        	 System.out.println(a2+"  "+b2);
	         }*/
	         if(a2==b2) {
	        	 f=Math.max(f, mid);
	        	 d=mid+1;
	         }
	         else {
	        	 e=mid-1;
	         }
	         
		}
		long jishu=2*f+1;
		d=0;
		 e=Math.min(b-1, c-b+1);
		 f=0;
		while(d<=e){
			int mid=(d+e)>>>1;
			long a4=jisuanhash(b-mid, b-1);
			long b4=jisuanhash2(b, b+mid-1);
			/*if(b==10) {
				System.out.println("EEE"+a4+"  "+b4+"  "+mid);
			}*/
			if(b4==a4) {
				f=Math.max(f, mid);
				d=mid+1;
			}
			else {
				e=mid-1;
			}
		}
		long oushu=2*f;
		
		long cccc=Math.max(oushu, jishu);
		answwer=Math.max(answwer, cccc);
	}
	pw1.println("Case "+a+":"+" "+answwer);
}
pw1.flush();
pw1.close();
	}
public static int aa=(int)(2e6+10);
public static long bb=131;
public static long cc=998244353;
public static long[] hash=new long[aa];
public static long[] hash2=new long[aa];
public static long[] jinzhi=new long[aa];
public static String ddString;
public static long jisuanhash2(int a,int b) {
	long c=0;
	c=((hash2[a]-hash2[b+1]*jinzhi[b-a+1])%cc+cc)%cc;
	return c;
}
public static long jisuanhash(int a,int b) {
	long c=0;
	c=((hash[b]-hash[a-1]*jinzhi[b-a+1])%cc+cc)%cc;
	return c;
}
public static void yuchuyi() {
	jinzhi[0]=1;
	int a=0;
	for(a=1;a<(1e6+67);a++) {
		jinzhi[a]=jinzhi[a-1]*bb%cc;
	}
}
public static void hashchuli(String aString) {
	int a=aString.length();
int b=0;
hash[0]=0;
for(b=1;b<=a;b++) {
	hash[b]=(hash[b-1]*bb+aString.charAt(b-1)-'a'+1)%cc;
}
	
}
public static void hash2chuli(String aString) {
	int a=aString.length();
	int b=0;
	hash2[a+1]=0;
	for(b=a;b>=1;b--) {
		hash2[b]=(hash2[b+1]*bb+(aString.charAt(b-1)-'a'+1))%cc;
	}
}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值