2014北京邀请赛 J 题 基于哈希值的LCP算法

题意:给定a和b两个字符串,有b匹配a在允许有两个字母不匹配而其他全匹配的情况下,找出第一个匹配的位置,若不能匹配,返回-1;

simple input 

3

aaabcd

abee


aaaaaa

aaaaa


aaaaaa

aabbb


simple output

Case #1: 2

Case#2:  0

Case#3:  -1

解题思路:

首先将b串接到a串的后面,利用LCP算法,进行匹配,中间最多有两次匹配不成功。

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

using namespace std;

typedef unsigned long long int ULL;
const int SIZE = 100003;
const int SEED = 13331;
const int maxn = 600100;
char s[maxn];
ULL H[maxn];
ULL XL[maxn];
int len;
void build(char *s) //求出字符串哈希值函数模板O(n)
{
    len=strlen(s);
    H[len]=0;
    XL[0]=1;
    for (int i=len-1; i>=0; i--)
    {
        H[i]=H[i+1]*SEED+s[i];
        XL[len-i]=XL[len-i-1]*SEED;
    }
}
ULL hash(int i,int L) //返回以i为开头的长度为L的字符串的哈希值(比较两个字符串的哈希值是否相等就可以判定两个字符串是不是相等)O(lgn)
{
    return H[i]-H[i+L]*XL[L];
}

int lcp(int i,int j)//二分,返回求取的以i和j开头的字符串的最大匹配的长度
{
    int l=0,r=min(len-i,len-j);
    int res=0;
    while (l<=r)
    {
        int mid=(l+r)/2;
        if (hash(i,mid)==hash(j,mid))
        {
            res=mid;
            l=mid+1;
        }
        else
        {
            r=mid-1;
        }
    }
    return res;
}

char A[maxn],B[maxn];
int main()
{
    int T;
    int cas=0;
    scanf("%d",&T);
    while (T--)
    {
        cas++;
        scanf("%s%s",A,B);
        int len1=strlen(A);
        int len2=strlen(B);
        if (len1<len2)
        {
            printf("Case #%d: -1\n",cas);
            continue;
        }
        int n=len1+len2+1;//合并两个字符串,中间加上一个保证不会在这两个串中出现的字符防止特殊情况
        for (int i=0; i<len1; i++) s[i]=A[i];
        for (int i=0; i<len2; i++) s[len1+1+i]=B[i];
        s[len1]='$';
        s[n]=0;
        build(s);
        int ans=-1;
        for (int i=0; i<=len1-len2; i++)
        {
            int st=i;
            int ed=len1+1;
            int tmp=lcp(st,ed);
            st+=tmp;
            ed+=tmp;
            if (ed>=n)//匹配到末尾了,下同
            {
                ans=i;
                break;
            }
            st++;
            ed++;//第一次匹配不成功
            if (ed>=n)
            {
                ans=i;
                break;
            }
            tmp=lcp(st,ed);
            st+=tmp;
            ed+=tmp;
            if (ed>=n)
            {
                ans=i;
                break;
            }
            st++;
            ed++;//第二次匹配不成功
            if (ed>=n)
            {
                ans=i;
                break;
            }
            tmp=lcp(st,ed);
            st+=tmp;
            ed+=tmp;
            if (ed>=n)
            {
                ans=i;
                break;
            }
        }
        printf("Case #%d: %d\n",cas,ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值