HDU 2594 EX_KMP或者字符串hash

题意:给你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 ;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值