【问题标题】:Longest Common Prefix property最长公共前缀属性
【发布时间】:2013-04-14 06:00:48
【问题描述】:

我正在研究后缀数组及其用于计算两个后缀的最长公共前缀。

消息来源说:

"两个后缀之间的 lcp 是数组上它们之间的所有相邻后缀对中 lcp 的最小值"

lcp(x,y)=min{ lcp(x,x+1),lcp(x+1,x+2),.....,lcp(y-1,y) } 其中 x 和 y 是字符串的两个索引,从字符串的两个后缀开始。

我不相信字符串 "abca" 示例中的陈述。

lcp(1,4)=1(考虑基于 1 的索引)

但是如果我应用上面的等式,那么

lcp(1,4)=min{lcp(1,2),lcp(2,3),lcp(3,4)}

我认为lcp(1,2)=0

所以根据等式,答案必须是0

我是不是哪里弄错了?

【问题讨论】:

    标签: string algorithm


    【解决方案1】:

    我认为源引用的索引不是字符串本身的索引,而是排序后缀的索引。

    a
    abca
    bca
    ca
    

    因此

    lcp(1,2) = lcp(a, abca) = 1
    lcp(1,4) = min(lcp(1,2), lcp(2,3), lcp(3,4)) = 0
    

    【讨论】:

    • 我只是想确认,对于后缀 x 和 y 的任何起始索引,lcp(x,y)=min{lcp(x,x+1,). ..lcp(y-1,y)} 或 x 和 y 也应该像 x' 和 y' 其中 x' 是后缀 x 的排序位置, y' 是后缀 y 的排序位置,即 lcp(x', y')=min(lcp(x',x'+1)...lcp(y'-1,y')}?
    【解决方案2】:

    你不能通过简单地计算数组上所有相邻后缀对的 lcp 的最小值来找到任何两个后缀的 LCP。

    我们可以计算任何后缀 (i,j) 的 LCP 在以下的帮助下:

    LCP(suffix i,suffix j)=LCP[RMQ(i + 1; j)]  
    

    还要注意(i<j)LCP (suff i,suff j) 不一定相等LCP (Suff j,suff i)。 RMQ 是范围最小查询

    paper 的第 3 页。

    Details:
    

    第 1 步: 首先计算相邻/连续后缀对的LCP。

    n= 字符串长度。

    suffixArray[] 为后缀数组。

    void calculateadjacentsuffixes(int n)
    {
        for (int i=0; i<n; ++i) Rank[suffixArray[i]] = i;
        Height[0] = 0;
        for (int i=0, h=0; i<n; ++i)
        {
            if (Rank[i] > 0)
            {
                int j = suffixArray[Rank[i]-1];
                while (i + h < n && j + h < n && str[i+h] == str[j+h])
                {
                    h++;
                }
                Height[Rank[i]] = h;
                if (h > 0) h--;
            }
        }
    }
    

    注意:Height[i]=LCPs of (Suffix i-1 ,suffix i) ie.高度数组包含相邻后缀的 LCP。

    第 2 步:

    使用 RMQ 概念计算任意两个后缀 i,j 的 LCP。 RMQ预计算功能:

    void preprocesses(int N)
    {
        int i, j;
    
        //initialize M for the intervals with length 1
        for (i = 0; i < N; i++)
            M[i][0] = i;
    
        //compute values from smaller to bigger intervals
        for (j = 1; 1 << j <= N; j++)
        {
            for (i = 0; i + (1 << j) - 1 < N; i++)
            {
                if (Height[M[i][j - 1]] < Height[M[i + (1 << (j - 1))][j - 1]])
                {
                    M[i][j] = M[i][j - 1];
                }
                else
                {
                    M[i][j] = M[i + (1 << (j - 1))][j - 1];
                }
            }
        }
    }  
    

    第三步:计算任意两个后缀 i,j 之间的 LCP

    int LCP(int i,int j)
    {
        /*Make sure we send i<j always */
        /* By doing this ,it resolve following
        suppose ,we send LCP(5,4) then it converts it to LCP(4,5)
        */
        if(i>j)
            swap(i,j);
    
        /*conformation over*/
    
        if(i==j)
        {
            return (Length_of_str-suffixArray[i]);
        }
        else
        {
            return Height[RMQ(i+1,j)];
            //LCP(suffix i,suffix j)=LCPadj[RMQ(i + 1; j)] 
            //LCPadj=LCP of adjacent suffix =Height.
        }
    }
    

    RMQ函数在哪里:

    int RMQ(int i,int j)
    {
        int k=log((double)(j-i+1))/log((double)2);
        int vv= j-(1<<k)+1 ;
        if(Height[M[i][k]]<=Height[ M[vv][ k] ])
            return M[i][k];
        else
            return M[ vv ][ k];
    }
    

    请参阅 Topcoder tutorials 了解 RMQ。

    您可以通过我的 blog 查看完整的 C++ 实现。

    【讨论】:

      猜你喜欢
      • 2021-09-11
      • 1970-01-01
      • 2022-11-22
      • 2018-09-30
      • 2012-02-01
      • 2020-07-05
      • 2020-02-10
      • 2022-01-11
      • 2021-10-12
      相关资源
      最近更新 更多