如何查找字符串的句点

时间:2014-01-16 17:43:12

标签: string algorithm substring

我接受来自用户的输入及其带有某个子串的字符串,该字符串在字符串中重复出现。我需要输出子串或其长度AKA周期。

S1 = AAAA // substring is A
S2 = ABAB // Substring is AB
S3 = ABCAB // Substring is ABC
S4 = EFIEFI // Substring is EFI

我可以从一个单一的字符开始并检查它是否与它的下一个字符相同,如果不是,我可以用两个字符然后用三个等来做它。这将是一个O(N ^ 2)算法。我想知道是否有更优雅的解决方案。

5 个答案:

答案 0 :(得分:7)

您可以通过归纳计算字符串的每个前缀的周期来在线性时间和恒定的额外空间中执行此操作。我无法回想起细节(有几件事情可以做到),但你可以在Section 13.6 of "Text algorithms" by Crochemore and Rytter under function Per(x)找到它们。

答案 1 :(得分:3)

我假设字符串n的长度至少是句点p的两倍。

<强>算法

  1. m = 1,S整个字符串
  2. m = m * 2
    • 查找子串S [:m]
    • 的下一个匹配项
    • k成为下一次出现的开始
    • 检查S [:k]是否为句号
    • 如果没有去2。
  3. 示例

    假设我们有一个字符串

    CDCDFBFCDCDFDFCDCDFBFCDCDFDFCDC
    

    对于2的每个幂m,我们会发现第一个2^m个字符的重复。然后我们将这个序列扩展到它的第二次出现。让我们从2 ^ 1开始CD

    CDCDFBFCDCDFDFCDCDFBFCDCDFDFCDC
    CDCD   CDCD   CDCD   CDCD   CD
    

    我们不会延长CD,因为下一次出现就在那之后。但是CD不是我们正在寻找的子字符串,所以让我们采用下一个功能:2^2 = 4和子串CDCD

    CDCDFBFCDCDFDFCDCDFBFCDCDFDFCDC
    CDCD   CDCD
    

    现在让我们将我们的字符串扩展到第一次重复。我们得到

    CDCDFBF
    

    我们检查这是否是周期性的。事实并非如此,我们走得更远。我们尝试2 ^ 3 = 8,所以CDCDFBFC

    CDCDFBFCDCDFDFCDCDFBFCDCDFDFCDC
    CDCDFBFC      CDCDFBFC      
    

    我们尝试扩展并获得

    CDCDFBFCDCDFDF
    

    这确实是我们的时期。

    我希望这可以在O(n log n)中使用一些类似KMP的算法来检查给定字符串的出现位置。请注意,仍然应该在这里解决一些边缘情况。

    直观地说这应该有效,但是我的直觉已经在这个问题上失败了所以如果我错了请纠正我。我会试着弄清楚。

    虽然是一个非常好的问题。

答案 2 :(得分:1)

您可以在线性时间内为整个字符串构建后缀树(后缀树很容易在线查​​找),然后递归计算并存储后缀树叶的数量(后缀前缀的出现)N(v)在后缀树的每个内部节点v下面。还递归地计算并存储树的每个节点处的每个后缀前缀L(v)的长度。然后,在树中的内部节点v处,在v处编码的后缀前缀是重复子序列,如果N(v)等于字符串的总长度除以L(v),则生成字符串。

答案 3 :(得分:0)

如果输入字符串中的每个字符都是重复子字符串的一部分,那么您所要做的就是存储第一个字符并将其与字符串的其余字符逐个进行比较。如果你找到一个匹配,字符串直到匹配一个是你的重复字符串。

答案 4 :(得分:0)

我也一直在寻找时空最优的解决方案。 accepted answer by tmyklebu本质上似乎就是它,但是我想对它的实质和进一步的发现提供一些解释。

首先,我提出的这个问题提出了一个看似有希望但不正确的解决方案,并附有错误原因的注释:Is this algorithm correct for finding period of a string?

通常,“查找时间段”问题等同于“在其内部查找模式”(在某种意义上为“ strstr(x+1,x)”),但是在结束时没有匹配的约束。这意味着您可以通过采用从左到右的任何字符串匹配算法,然后将其应用到自身,并考虑部分匹配项(该匹配项会打到干草堆/文本的末尾)作为匹配项,从而找到时间段,并且时间和空间要求与您使用的任何字符串匹配算法都相同。

tmyklebu的答案中引用的方法本质上是将此原理应用于String Matching on Ordered Alphabets,也适用于explained here。使用GS algorithm可以实现另一种时空最佳解决方案。

不幸的是,众所周知的,简单的Two Way算法(也是explained here)不是解决方案,因为它不是从左到右的。特别地,在左因子不匹配之后的进展取决于右因子已经是匹配,并且另一匹配不可能与右因子以模为右因子的周期为模而失准。当在自身中搜索模式并无视末尾的内容时,我们无法就下一次正确因子匹配的发生时间得出任何结论(部分或全部正确因子可能已移出模式末尾),因此无法进行保留线性时间的移位。

当然,如果有可用的工作空间,则可以使用许多其他算法。 KMP是具有O(n)空间的线性时间,并且可能仅使用对数空间就可以将其调整为仍然相当有效的事物。