模板总结——基于哈希的LCP问题

问题引入

求第i位开始的后缀和第j位开始的后缀的最长公共前缀的长度?

高度数组&&RMQ

求出高度数组lcp,假设rank[i]小于rank[j],那么后缀i和后缀j的LCP值等于min{lcp[rank[i],lcp[rank[i+1],…lcp[rank[j]-1}.
预处理RMQ即可O(1)查询LCP值。但由于是预处理RMQ,无法动态回答LCP回答。也就是说一旦题目中有对字符串修改的操作,则此方法无法解决。

基于哈希的LCP

给每一个子串一个哈希值,这样子串改变时只需对应地修改哈希值即可。
定h(i)表示后缀S[i…]的哈希值。
定义hash(i,L)表示以i为起始位置、长度为L的子串的哈希值。

h(n-1)=s[n-1] 边界
h(i)=h(i+1)*x+s[i] 递推
一般地,

h[i]=s[i]+s[i+1]*x+s[i+2]*x^2+...+s[n-1]*x^(n-1-i);

hash(i,L)的哈希值定义如下

hash(i,L)=s[i]+s[i+1]*x+s[i+2]*x^2+...+s[i+L-1]*x^(L-1)

推导后,

hash(i,L)=h[i]-h[i+L]*x^L;

所以预处理h和x^L后就可以在常数时间内计算出hash(i,L)。hash值可能很大,这里用unsigned long long去存,这样在算术运算时会自然溢出,相当于模2^64.

解决问题:
二分答案L,如果hash(i,L)==hash(j,L),那么就认为以LCP(i,j)>=len.

模板

const int x=123;//随便取一个x
unsigned long long h[maxn],xp[maxn];
int n;
string s;

void get_hxp()
{
    n=s.size();
    h[n]=0;
    for(int i=n-1;i>=0;i--)
        h[i]=h[i+1]*x+s[i]-'a';
    xp[0]=1;
    for(int i=1;i<=n;i++)
        xp[i]=xp[i-1]*x;
}
unsigned long long Hash(int i,int L)
{
    return h(i)-h(i+L)*xp[L];
}
阅读更多
个人分类: 后缀数组
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭