【问题标题】:How does this code for obtaining LCP from a Suffix Array work?从 Suffix Array 获取 LCP 的代码如何工作?
【发布时间】:2014-10-17 15:41:10
【问题描述】:

有人能解释一下这个从后缀数组构造 LCP 的代码是如何工作的吗? suffixArr[] 是一个数组,这样suffixArr[i] 保存字符串中具有等级 i 的后缀的索引值。

 void LCPconstruct()
{
    int i,C[1001],l;
    C[suffixArr[0]] = n;


    for(i=1;i<n;i++)
    C[suffixArr[i]] = suffixArr[i-1];

    l = 0;

   for(i=0;i<n;i++)
   {
    if(C[i]==n)
        LCPadj[i] = 0;
    else
    {
        while(i+l<n && C[i]+l<n && s[i+l] == s[C[i]+l])
            l++;
        LCPadj[i] = l;

        l = max(l-1,0);
    }
  }

  for(i=0;i<n;i++)
     cout<<LCPadj[suffixArr[i]]<<"\n";


}

【问题讨论】:

  • 嗯,你从哪里弄来的?
  • 我正在查看关于 codechef 的问题的解决方案。 codechef.com/problems/MOU1H
  • 关于解决方案的长篇社论并没有帮助您理解它是如何工作的?写的很详细。
  • 其实我看到了一个用户的代码,因为我创建后缀数组的方法最接近他的。社论中使用的方法完全不同。
  • 我不确定我们在这里是如何使用 l 的。每次迭代后它都会更新为 max(l-1,0),而不是每次都从 0 开始。

标签: c++ algorithm suffix-array


【解决方案1】:

首先,重要的是要认识到算法按原始顺序处理后缀,即它们在输入字符串中出现的顺序。不按字典顺序。

所以如果输入字符串是abxabc,它首先考虑abxabc,然后是bxabc,然后是xabc,以此类推。

对于它按此顺序考虑的每个后缀,它确定作为其词典前身的后缀的位置(*)(所以在这里,也只有在这里,它使用了词典顺序的概念) .对于第一个后缀abxabc,词典前身,即在后缀的词典顺序中直接出现在它之前的后缀是abc。它通过在数组C 中进行 O(1) 查找来确定这一点,该数组专门为此目的而准备。

内部循环将abxabcabc的字符一一进行比较,判断这两个后缀的前2个字符是相同的。这是你代码中的变量l,这意味着后缀abxabc在LCP中的条目必须是2,所以我们设置LCPadj[i] = l。注意这里的i是指后缀在输入字符串中的位置,而不是它在后缀数组中的位置。所以LCPadj 还不是 LCP 阵列。它是一种辅助数据结构。

然后它继续到下一个字符串,即bxabc。它再次使用C 来查找bc 是它的词典前身,然后确定两者共享多少前缀字符。诀窍来了:可以确定这必须至少与上一步中的一样多(即 2),减去 1。为什么?因为我们当前考虑的字符串bxabc,当然是之前考虑的字符串(abxabc)的后缀,因此该字符串的词典前身(abc)也必须有一个短1个字符的后缀( bc),并且该后缀也必须在后缀数组中的某个位置,并且它必须与当前考虑的字符串共享其前缀,减去第一个字符。此外,不可能有任何其他后缀更短且在字典上更接近当前考虑的字符串。如果您考虑字典排序的工作原理,后者是很合乎逻辑的,但也有正式的证明(例如,Kärkkäinen 的讲座中的引理 5.10 here

所以这描述了这里的主要工作原理。为了充分理解每个变量的作用,您的代码有几点需要注意:

  • 正如所解释的,C 是一个辅助数组(长度为n 整数),它为输入字符串中的每个后缀存储作为其直接词典前身的其他后缀的位置。这个数组不是从左到右构造的,而是(明智地)通过从左到右遍历后缀数组来构造的,因为这样可以很容易地确定任何字符串的直接词典前身: 后缀的直接词典前身从位置开始suffixArr[i] 当然必须位于位置suffixArr[i-1]。在您的代码中确认这是 C 的定义方式。
  • 如上所述,LCPadj 按它们在输入字符串中出现的顺序存储后缀的 LCP 值,而不是它们在后缀数组中出现的顺序。这就是为什么在输出时,LCPadj 不是从左到右打印,而是通过从左到右遍历后缀数组,并按该顺序打印 LCPadj[i]。确认是这种情况。

我希望这会有所帮助。如果没有,请告诉我。


(*)按字典顺序排列的前辈是指按字典顺序排列的后缀列表中的后缀的直接前辈,即后缀它在后缀数组中的最左边。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-17
    • 2018-03-26
    • 1970-01-01
    • 2018-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多