POJ 2774 二分+Hash+二分

题意

给定两个字符串(length<=1e5),求最长公共子串。

思路

根据最长公共子串的单调性,可知如果两个串存在长度为k的公共子串,那么必定存在长度为0~k-1的公共子串。

所以我们可以 二分最长公共子串的长度,然后进行验证,即对于串1的长度为len的每个子串,是否在串2中出现,也是二分查找。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
typedef unsigned long long ull;
const int maxlen = 1e6+5; 
const int maxn = 1e5+5;
ull h[maxn],h1[maxn],h2[maxn];

char s1[maxlen],s2[maxlen];
int len1,len2;

ull pow(ull x,ull y){
	ull ans = 1;
	while(y){
		if(y&1) ans = ans*x;
		x *= x;
		y >>= 1;
	}
	return ans;
}
int check(int len){
	ull p = pow((ull)133,(ull)len);
	for(int i=len;i<=len1;i++)
		h[i-len] = h1[i]-h1[i-len]*p;
	sort(h,h+len1-len+1);
	
	for(int i=len;i<=len2;i++)
		if(binary_search(h, h+len1-len+1, h2[i]-h2[i-len]*p)) return 1;	
	return 0;
}

int main(){
	while(~scanf("%s",s1)){
		scanf("%s",s2);
		len1 = strlen(s1),len2 = strlen(s2);
		h1[0] = 0;
		for(int i=1;i<=len1;i++)
			h1[i] = h1[i-1]*133 + s1[i-1];
		
		h2[0]=0;
		for(int i=1;i<=len2;i++)
			h2[i] = h2[i-1]*133 + s2[i-1];
				
		int l=1,r=min(len1,len2)+1,mid;//binary sub length
		int ans = 0;
		while(l < r){
			mid = l + (r-l)/2;
			if(check(mid)){
				ans = mid;
				l = mid+1;
			}
			else r = mid;
		}
		printf("%d\n",ans);
	}	
	return 0;
}

优化参考:https://blog.csdn.net/HTT_H/article/details/42840917

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值