【后缀数组】 POJ 2774 Long Long Message 两个字符串的最长公共子串长度

本文介绍了一种高效的字符串匹配算法,该算法通过计算高度数组并结合两串相接的方法来寻找最长公共子串。文章详细展示了算法的实现过程,并提供了完整的C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

点击打开链接

两串相接

先判断sa[i]与sa[i-1]属于不同串 再取height[i] 的最值

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <queue>
#include <stack>
#include <vector>
#include <list>
#include <deque>
#include <set>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
typedef long long LL;
const int INF = 1<<29;
const int mod = 2552 ;
const int MAXN = 210000;
int t1[MAXN],t2[MAXN],c[MAXN]; //求SA数组需要的中间变量,不需要赋值
//待排序的字符串放在s数组中,从s[0] 到s[n-1], 长度为n, 且最大值小于m,
//除s[n-1] 外的所有s[i] 都大于0, r[n-1]=0
//函数结束以后结果放在sa数组中
bool cmp(int *r, int a, int b, int l)
{
    return r[a] == r[b] && r[a+l] == r[b+l];
}
void da(int str[], int sa[], int rank[], int height[], int n, int m)
{
    n++;
    int i, j, p, *x = t1, *y = t2;
//第一轮基数排序,如果s的最大值很大,可改为快速排序
    for(i = 0; i < m; i++)c[i] = 0;
    for(i = 0; i < n; i++)c[x[i] = str[i]]++;
    for(i = 1; i < m; i++)c[i] += c[i -1];
    for(i = n-1; i >= 0; i--)sa[ --c[x[i]]] = i;
    for(j = 1; j <= n; j <<= 1)
    {
        p = 0;
//直接利用sa数组排序第二关键字
        for(i = n-j; i < n; i++)y[p++] = i; //后面的j 个数第二关键字为空的最小
        for(i = 0; i < n; i++) if(sa[i] >= j)y[p++] = sa[i] - j;
//这样数组y保存的就是按照第二关键字排序的结果
//基数排序第一关键字
        for(i = 0; i < m; i++)c[i] = 0;
        for(i = 0; i < n; i++)c[x[y[i]]]++;
        for(i = 1; i < m; i++)c[i] += c[i-1];
        for(i = n-1; i >= 0; i --)sa[--c[x[y[i]]]] = y[i];
//根据sa和x数组计算新的x数组
        swap(x,y);
        p = 1;
        x[sa[0]] = 0;
        for(i = 1; i < n; i++)
            x[sa[i]] = cmp(y,sa[i -1],sa[i],j)?p- 1:p++;
        if(p >= n) break;
        m = p; //下次基数排序的最大值
    }
    int k = 0;
    n--;
    for(i = 0; i <= n; i++)rank[sa[i]] = i;
    for(i = 0; i < n; i++)
    {
        if(k)k--;
        j = sa[rank[i] -1];
        while(str[i+k] == str[j+k])k++;
        height[rank[i]] = k;
    }
}
int rank[MAXN],height[MAXN];
char str[MAXN],st[MAXN];
int r[MAXN];
int sa[MAXN];
int solve(int x,int len1,int len2)
{
    if(sa[x]<=len1&&sa[x-1]>len1)
        return 1;
    if(sa[x-1]<=len1&&sa[x]>len1)
        return 1;
    return 0;
}
int main()
{
    scanf("%s%s",str,st);
    int n;
    int len1=strlen(str);
    int len2=strlen(st);
    for(n=0;str[n];n++)
        r[n]=str[n];
    r[n++]=0;
    for(int i=0;st[i];i++)
        r[n++]=st[i];
    da(r,sa,rank,height,n,128);
    int ans=0;
    for(int i=2;i<=n;i++)
        if(height[i]>ans&&solve(i,len1,len2))
            ans=height[i];
    cout<<ans<<endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值