繁体   English   中英

给定一个字符串s和一个较小字符串数组T,如何设计一个方法来搜索T中每个小字符串的s?

[英]Given a string s and an array of smaller strings, T, how to design a method to search s for each small string in T?

给定一个字符串s和一个较小字符串数组T,设计一种方法来搜索s中T中的每个小字符串。

谢谢。

假设你有大量较小的字符串, Rabin-Karp是在非常大的字符串中搜索多个小字符串的标准方法。 如果你只有一些较小的字符串,只需重复一个Boyer-Moore ,这可能是一个更好的选择。

我所知道的解决这个问题的最快方法是Aho-Corasick算法 对于要搜索的大字符串和大量模式,它比为每个模式应用线性时间搜索(例如KMP,Rabin-Karp,Boyer-Moore)更快。

但是你确定你需要这样的东西,你的字符串太长了,不能直接进行字符串匹配吗?

这听起来像一个简单的for循环:

for(string t : T)
{
    if (t.equals(s)) {
        /* do stuff with t */
    }
}

如何使用For Each循环

如果不了解有关数据集的更多详细信息,则无法选择“最佳”算法。

  • 这些统计上是随机的字符串吗?
  • 小字符串中有很多或一点点重复吗?
  • 您想优化执行速度还是低内存消耗?
  • 您是否会使用相同的子字符串(T)或相同的主字符串多次执行此搜索?

没有这些信息,“最佳”解决方案是最简单的解决方案。

static IEnumerable<string> FindIn(this IEnumerable<string> T, string s) {
    return T.Where(t => s.Contains(t));
}

你能澄清一下吗?

**算法将强烈取决于“搜索”的含义。 **

  • 你想知道T中的每个字符串是否是S的正确子字符串? 还是任何字符串?

  • 您需要是/否答案还是索引?

  • 您是否关心答案是否重叠(例如“ABCDE”包含“ABC”和“CDE”,但仅在您不关心重叠时)。

一种简单的方法(假设搜索字符串都以相当不同的方式开始)是:

  • 有一个“第一个字符”=> map_of_first_2_characters__to__list_of_strings的地图。

  • 循环遍历S中的每个位置,在上面的地图中找到该字符作为键。

    • 该值将是另一个映射,将2个字符的字符串映射到以这2个字符开头的子字符串列表。

    • 在子图中查找字符及其右邻居,该值将是以这两个值开头的字符串列表。

    • 假设T和T中的起始字符分布相当均匀(如果它太大,仅仅通过映射3个字符来构建数据结构一层) - 我们刚刚找到了一个非常短的合理匹配列表,从当前开始位置。 字符串 - 比较它们。 标记从当前位置开始的S的子串(如果有的话)。 如果目标不是找到所有字符串的所有匹配项,则从数据结构中删除您找到的匹配项。

您可能希望阅读此内容以获取高级内容

让我们把它变成一个Java解决方案

boolean isSubset(String[] t, String s) {
    for (String sample: t)
        if (!sample.equals(s))
            return false;
    return true;
}

你可以使用Falaina的建议加快速度,但你真的需要吗?

如果你有一个指针表空间(指针大小* NumCharsInSource),你可以使用像QSort这样的东西对源中的每个字符串(字符串开头的字符串)进行排序。 然后,您可以将较小的字符串BSearch到指针表中。 假设N个字符和M个子串,排序将具有O(N lg N)性能,并且查找将具有O(M lg N)性能。 总体性能应为O((N + M)lg N)。

但是,可能存在退化情况,其中源中的字符串是高度重复的(即100,000个a后跟ab)。 这将使排序部分的比较非常缓慢:-(为了解决这个问题,你可以特殊情况下长时间运行字符,但这会变得更加复杂。

选择的算法实际上取决于您的源数据以及您必须使用多少备用内存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM