给定一个长字符串数组,如果它们最多相差一个字符,我如何有效地检查给定的子字符串对(给定字符串的)?

Posted

技术标签:

【中文标题】给定一个长字符串数组,如果它们最多相差一个字符,我如何有效地检查给定的子字符串对(给定字符串的)?【英文标题】:Given an array of long strings, how do I efficiently check given pairs of substrings (of the given strings) if they differ by at most one character? 【发布时间】:2019-08-26 04:09:00 【问题描述】:

任何给定的子串对都具有相同的长度。必须检查许多对子字符串,因此简单的比较不够有效,但我真的想不出任何有助于加快比较过程的字符串数组的预处理。提前致谢!

举个例子说明一下:

一个长字符串数组:

str = "aaaaa", "aaabbcc", "abcdefgh"...

要检查的子串对:

pairs = (str[0][0..1],str[1][1..2]), (str[0][1..4],str[2][3..6]), (str[1][2..4], str[2][0..2])...

要检查(替换)的子串对:

pairs = ("aa","aa"), ("aaaa","defg"), ("abb","abc")...

最终结果:

result = true, false, true

天真的比较会导致运行时间为O(|pairs|*max(|str[i]|)),我想改进它。

【问题讨论】:

你能展示一下你目前拥有的代码吗? 有a variety of algorithms 执行子字符串搜索比简单地比较每对子字符串更快。我建议查看一些内容以尝试确定一个可以修改以服务于您的目的的内容。它仍然会很昂贵,但 N^3 比 N^4 好。 @MrPromethee 除了进行简单的字符串匹配之外,我没有做太多事情。我还做了一个校验和,所以我只匹配校验和差异小于 128 (ascii) 的字符串。尽管如此,这并没有改善最坏的情况,即所有对子字符串恰好相同/不同一个字符。 您是否在每个长字符串中寻找匹配的子字符串?还是跨越所有长字符串?还是在他们两个之间?是否给出了子字符串的长度,即输入值? @MOehm 给出一对子字符串及其各自的索引,例如 str[4] [7..25](第 7 到第 25 个字符的第 4 个字符串)和 str[9][ 0..18](第 0 到第 18 个字符的第 9 个字符串),并且提供了许多对。 【参考方案1】:

(在这里交叉发布我从 Quora 的答案)。

IMO,这个问题没有说得很清楚,但我认为它似乎在问以下问题:给定一组字符串 S[1]、S[2]、...、S[N] 和一个一组查询,每个查询都采用 (i1, j1, i2, j2, L) 形式。如果从 S[i1] 的位置 j1 和 S[i2] 的位置 j2 开始的长度为 L 的字符串最多相差一个字符,则该查询的答案是“是”,否则为“否”。所有此类查询的 L 值之和可能远大于字符串的总长度。

在这种情况下,我们可以使用以下观察设计一个有效的算法:如果 S 和 T 是长度为 L 的字符串,那么语句“S 和 T 最多相差一个字符”等价于“LCP (S, T) + LCP(R(S), R(T)) >= L-1” 其中R表示一个字符串的反转,LCP是两个字符串的最长公共前缀的长度。

因此,为了有效地回答查询,我们只需要对字符串 S[1], ..., S[N] 和 R(S[1]), ..., R(S[N]) 进行预处理,以便最长公共前缀查询很快。这可以通过连接 S[1], ..., S[N] 来给出一个字符串 S,并构建 S 的 suffix array 和 longest-common-prefix array 来完成,然后对 S 的反向执行相同的操作。确定 LCP那么原始字符串的两个子串就相当于确定了S(*)的两个子串的LCP,相当于LCP数组中的一个range-minimum-query,可以通过预处理来有效地回答。类似的语句适用于原始字符串的反转和 S 的反转。

(*) 从技术上讲,连接字符串 S 中的 LCP 可以超出原始字符串的边界。但是,这只会在查询子字符串实际上相同的情况下发生,所以这只是意味着我们会在答案为“是”的情况下回答“是”。

【讨论】:

【参考方案2】:

您可以尝试使用后缀树:https://en.wikipedia.org/wiki/Suffix_tree

首先将所有字符串转换为后缀树。这可以在 O(n) 时间内完成,其中 n 是字符串的长度。

然后你可以递归地尝试所有可能的字符串,看看它们是否是至少2个字符串的子字符串。

您从一个包含指向所有树根的指针的集合开始。这反映了 '' 是所有字符串的子字符串。然后为每个 char 找到具有匹配子节点的树的子集。例如。对于“a”,找到集合中所有具有标记为“a”的子项的指针。对于任何非空集,您都找到了一个新的公共子字符串,然后您递归检查更长的子字符串。

如果您想允许一个差异,则递归调用还必须包括到目前为止的差异数量。如果为 1,则只允许匹配的孩子。如果它为 0,那么您还可以对每一对 (c1, c2) 进行递归,其中一个字符串有一个子 c1,而其他一些字符串有一个子 c2。

我认为它的整体运行时间为 O(n * m + m * k * m * l) 其中 n 是字符串的最大长度,m 是它们的数量,k 是您找到的子字符串的数量,l 是您找到的子字符串的最大长度。

【讨论】:

感谢您的努力,但恐怕这不是我想要的。我的问题是我有一堆长度相等的给定子字符串(长字符串数组),如果这对子字符串相差一个或更少的字符,我想比较它们。 naive 方法的运行时间为 O(nm),其中 n 是对数,m 是子字符串的最大长度。我希望某种预处理可以将时间复杂度降低到低于 O(nlog(m))。 这毫无意义。为什么要让它与子字符串的长度成对数呢?绕过我看到的幼稚运行时的唯一方法是当给定的子字符串以多对出现时。然后上述内容将适用。

以上是关于给定一个长字符串数组,如果它们最多相差一个字符,我如何有效地检查给定的子字符串对(给定字符串的)?的主要内容,如果未能解决你的问题,请参考以下文章

两个字符串几乎相等

找到给定字符串的每个可能的子集[重复]

做一个无前缀的集合

常用数据结构

如何使用基数排序对变长字符串数组进行排序?

如何在给定位置从动态分配的数组中打印字符串