【问题标题】:To find all the repeating substring in a given string查找给定字符串中的所有重复子字符串
【发布时间】:2012-04-20 18:04:46
【问题描述】:

我最近遇到一个面试问题: 查找给定字符串中最小大小为 2 的所有重复子字符串。 该算法应该是有效的。

下面给出了上述问题的代码,但效率不高。

#include <iostream>
#include <algorithm>
#include <iterator>
#include <set>
#include <string>

using namespace std;

int main()
{
    typedef string::const_iterator iterator;
    string s("ABCFABHYIFAB");
    set<string> found;

    if (2 < s.size())
        for (iterator i = s.begin() + 1, j = s.end(); i != j; ++i)
            for (iterator x = s.begin(); x != i; ++x)
            {
                iterator tmp = mismatch(i, j, x).second;;
                if (tmp - x > 1)
                    found.insert(string(x, tmp));
            }

            copy(found.begin(), found.end(),ostream_iterator<string>(cout, "\n"));
}

我的问题是,有没有什么数据结构可以及时实现上述问题 O(N)的复杂度?

如果您的答案是后缀树或散列,请详细说明。

【问题讨论】:

  • 如果我理解正确,您认为输出中的两个(大小相等)子字符串不同,如果它们的起始索引不同,而不是它们的内容不同,对吧?
  • 阅读后缀树,在我看来,wiki 是一个好的开始:en.wikipedia.org/wiki/Suffix_tree
  • @dexametason 您正在建议最好的解决方案。重复的子字符串是 CS 中非常常见的问题。您能否将此作为解决方案发布?这将对网站访问者非常有帮助。干杯!
  • @MonsterTruck 因为我看到接受的答案在我的评论之后包含相同的内容,所以我不想重复它作为答案。也许应该将某些链接添加到已接受的答案中。

标签: c++ string algorithm


【解决方案1】:

我不知道后缀树如何获取所有重复的子串,字符串“mississippi”这样构建后缀树:

对不起,我明白了。 “最后,遍历 count>1 的每个节点并打印其路径。” “count”是这个子节点的数量

tree-->|---mississippi               m..mississippi
       |
       |---i-->|---ssi-->|---ssippi   i .. ississippi
       |       |         |
       |       |         |---ppi      issip,issipp,issippi
       |       |
       |       |---ppi                ip, ipp, ippi
       |
       |---s-->|---si-->|---ssippi    s .. ssissippi
       |       |        |
       |       |        |---ppi       ssip, ssipp, ssippi
       |       |
       |       |---i-->|---ssippi     si .. sissippi
       |               |
       |               |---ppi        sip, sipp, sippi
       |
       |---p-->|---pi                 p, pp, ppi
               |
               |---i                  p, pi

--- Suffix Tree for "mississippi" ---

【讨论】:

  • 你是如何建造那棵树的?
【解决方案2】:

如果你分析字符串"AAAAAAAAAAAAAA"的输出,那么里面有O(n²)个字符,所以算法至少是O(n²)。

要实现 O(n²),只需为 s 的每个后缀构建suffix tree(索引 [1..n]、[2..n]、[3..n]、...、[n ..n])。如果其中一个字符串没有自己的结束节点并不重要,只需计算每个节点的使用频率即可。

最后,以 count>1 遍历每个节点并打印其路径。

【讨论】:

    【解决方案3】:

    这只是一个疯狂的想法,但值得一试(但是,它消耗 O(N) 内存,其中 N 是主字符串的长度)。算法不是O(N),但也许可以优化。

    这个想法是,您不想经常进行字符串比较。您可以收集读取数据的哈希值(例如读取字符的 ASCII 码总和)并比较哈希值。如果哈希值相等,则字符串可能相等(必须稍后检查)。例如:

    ABCAB
    
    A -> (65)
    B -> (131, 66)
    C -> (198, 133, 67)
    A -> (263, 198, 132, 65)
    B -> (329, 264, 198, 131, 66)
    

    因为您只对 2+ 长度值感兴趣,所以您必须省略最后一个值(因为它始终对应于单个字符)。

    我们看到两个相等的值:131 和 198。131 代表 AB 并显示这对,但是 198 代表 ABC 和 BCA,必须通过手动检查来拒绝。

    这只是想法,而不是解决方案本身。可以扩展散列函数以考虑字符在子字符串(或序列结构)中的位置。可以更改哈希值的存储方法以提高性能(但是会增加内存使用量)。

    希望我能帮上一点忙 :)

    【讨论】:

      猜你喜欢
      • 2015-12-31
      • 2017-08-05
      • 2019-03-29
      • 2016-04-20
      • 1970-01-01
      • 2017-05-26
      • 1970-01-01
      • 2023-01-19
      • 2014-05-09
      相关资源
      最近更新 更多