题意:给你2个字符串a , b 。问 a的前缀和b的后缀的公共部分最长是多少。
思路:把a从前往后hash,把b从后往前hash,如果hash值相等,那么代表两个字符串相等,那么更新长度。
最后输出这个长度的最大值即可。
还可以用EX_KMP搞,我们可以把两个字符串连成一个,然后根据EX_KMP的NEXT数组的作用,直接就可以判断后缀是否等于前缀。
先来一发HASH的代码。
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x7fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
using namespace std;
#define uint unsigned int
#define N 55555
char a[N] , b[N] ;
int main() {
while(scanf("%s%s",a,b) != EOF){
int la = strlen(a) ;int lb = strlen(b) ;
uint seed = 31 , hasha = 0 , hashb = 0 , Hx = 1 ;
int posa = 0 , posb = lb - 1 ;
int ans = -1 ;
while(posa < la && posb >= 0){
hasha = hasha * seed + a[posa] ;
hashb = hashb + Hx * b[posb] ;
hasha &= inf ;
hashb &= inf ;
if(hasha == hashb)ans = posa + 1 ;
Hx *= seed ;
posa ++ ;
posb -- ;
}
for (int i = 0 ; i < ans ; i ++ )cout << a[i] ;
if(ans == -1)cout << 0 << endl;
else cout<< " " << ans << endl;
}
return 0;
}
再来一发EX_KMP的代码。
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
using namespace std;
#define N 111111
int Next[N] ;
char b[N] ;
void EX_Next(){
int x = 0 ;
int l = strlen(b) ;
Next[0] = l ;
while(x < l - 1 && b[x] == b[x + 1])x ++ ;
Next[1] = x ;
x = 1 ;
for (int k = 2 ; k < l ; k ++ ){
int p = x + Next[x] - 1 , L = Next[k - x] ;
if(k - 1 + L >= p){
int j = (p - k + 1) > 0 ? (p - k + 1) : 0 ;
while(k + j < l && b[k + j] == b[j]) j ++ ;
Next[k] = j ;
x = k ;
}else {
Next[k] = L ;
}
}
}
int main() {
while(scanf("%s",b) != EOF){
int l = strlen(b) ;
scanf("%s",b + l) ;
EX_Next() ;
int l1 = strlen(b) ;int ans = -1 ;
for (int i = l ; i < l1 ; i ++ ){
int now = Next[i] ;
if(i + now == l1)
ans = max(ans , now ) ;
}
ans = ans >= l ? l : ans ;
for (int i = 0 ; i < ans ; i ++ )cout << b[i] ;
if(ans == -1)cout << 0 << endl ;
else cout << " " << ans << endl;
}
return 0;
}
HDU 1867 同样的意思,给定两个字符串,找出一个串的前缀和一个串的后缀的最大重复字串,然后将两个串合起来,当然重叠部分算一次,然后输出最后的串。
注意的是这道题两个字符串哪个在前那个在后不知道,所有做两次EX_KMP,分别求出各串最为前缀和后缀能匹配的最大长度,最后输出长度小字典序小的那个即可。
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
using namespace std;
#define N 211111
int Next[N] ;
void EX_NEXT(char *a) {
int l = strlen(a) ;
int x = 0 ;
Next[0] = l ;
while(x < l - 1 && a[x] == a[x + 1]) x ++ ;
Next[1] = x ;
x = 1 ;
for (int k = 2 ; k < l ; k ++ ) {
int p = x + Next[x] - 1 , L = Next[k - x] ;
if(k - 1 + L >= p) {
int j = (p - k + 1) > 0 ? (p - k + 1 ) : 0 ;
while(k + j < l && a[k + j] == a[j]) j ++ ;
Next[k] = j ;
x = k ;
} else Next[k] = L ;
}
}
string gao(char *x , char *y){
int l1 = strlen(x) , l = l1 , posy = 0 ;
while(y[posy])x[l ++ ] = y[posy ++ ] ;
x[l] = '\0' ;EX_NEXT(x) ;int l2 = strlen(x) ;int num = 0 ;
for (int i = l1 ; i < l2 ; i ++ )
if(i + Next[i] == l2)num = max(num , Next[i]) ;
string ff = y ;
while(x[num] && num < l1)ff += x[num ++] ;
return ff ;
}
char a[N] , b[N] ;
char x[N] , y[N] ;
string check(string ans , string tans){
if(ans.size() > tans.size())return tans ;
if(ans.size() < tans.size())return ans ;
return ans > tans ? tans : ans ;
}
int main() {
while(scanf("%s%s",b,a) != EOF) {
strcpy(x , a) ;strcpy(y , b) ;
printf("%s\n",check(gao(a , b) , gao(y , x)).c_str()) ;
}
return 0 ;
}