poj2217详解 ( 后缀数组 + 高度数组 )

题目大概意思就是 给两个字符串,求最长公共字符串子串长度

我们可以考虑用后缀数组和高度数组
一个字符串 中 最长的两个相同字符串长度, 不就是 后缀数组中相邻两个后缀的最长公共前缀, 不就是 高度数组的最大值
这不就与题意很相似了,我们只需要把两个字符串连接在一起就可以了

然后我们比较高度数组的大小即可

需要注意:

  1. 因为比较高度数组时,可能两个相邻的后缀是在同一个字符串中,所以我们需要先判断后缀是从哪开始的
  2. 这时候又会出现另一种情况,可能有个后缀经过了两个字符串,这种情况判断,两个后缀是从不同字符串开始的,无法判断出来,所以我们要在连接两个字符串时,在中间加上一个在字符串中不会出现的字符 ( 例:S = a + ‘\0’ + b )
#include <iostream>
#include <stdio.h>
#include <string>
#include <algorithm>
using namespace std;
string S;
int sa[20005], rk[20005], tmp[20005], lcp[20005];
int k;
bool cmp(int a, int b)
{
    if(rk[a] == rk[b])
    {
        int i = a + k <= S.length() ? rk[a + k] : -1;
        int j = b + k <= S.length() ? rk[b + k] : -1;
        return i < j;
    }
    return rk[a] < rk[b];
}
void construct_sa()
{
    for(int i = 0; i <= S.length(); i++)
    {
        sa[i] = i;
        rk[i] = i < S.length() ? S[i]: -1;
    }
    for(int i = 1; i <= S.length(); i = i * 2)
    {
        k = i;
        sort(sa, sa + S.length() + 1, cmp);
        tmp[sa[0]] = 0;
        for(int i = 1; i <= S.length(); i++)
        {
            tmp[sa[i]] = tmp[sa[i-1]] + (cmp(sa[i-1], sa[i]) ? 1 : 0);
        }
        for(int i = 0; i <= S.length(); i++)
        {
            rk[i] = tmp[i];
        }
    }
}
void construct_lcp()
{
    int h = 0;
    for(int i = 0; i < S.length(); i++)
    {
        int j = rk[i] - 1;
        if(h != 0) h--;
        while(i + h < S.length() && sa[j] + h < S.length() && S[sa[j]+h] == S[i+h]) h++;
        lcp[j] = h;
    }
}
int main()
{
    int T;
    scanf("%d", &T);
    getchar();
    while(T--)
    {
        string a, b;
        getline(cin, a);
        getline(cin, b);
        int n = a.length();
        S = a + '\0' + b;
        construct_sa();
        construct_lcp();
        int res = 0;
        for(int i = 0; i < S.length(); i++)
        {
            if((sa[i] < n) != (sa[i+1] < n))
            {
                res = max(res, lcp[i]);
            }
        }
        printf("Nejdelsi spolecny retezec ma delku %d.\n", res);
    }
}

可能你会觉得如果 子字符串 a 和 b( 在不同字符串中 )有最长公共字符串子串长度,这时如果有个和 b 在同一个字符串的 子字符串 c,如果 b 与 c 的最长公共字符串子串长度更长,会不会影响判断?
这个当然不会,如果在后缀数组排序中是 a b c,这自然不会影响,如果是 a c b,则 a 与 b 相同的前缀,c 一定也有相同的前缀,所以自然也不会影响

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值