C++ 在';中查找最长公共子字符串的长度;n';二进制串
我被赋予C++ 在';中查找最长公共子字符串的长度;n';二进制串,c++,string,algorithm,optimization,longest-substring,C++,String,Algorithm,Optimization,Longest Substring,我被赋予n字符串(n>=2和nn; 对于(i=1;i>a[i]; if(a[i].length()方法)将对象的地址与之前看到的对象进行比较。在C++中,有一组指针元组用于相同的目的。答案是分别构建所有字符串的后缀树,然后将它们相交。后缀树就像一个trie,同时包含一个字符串的所有后缀 为固定字母表建立后缀树是O(n)with。(如果你不喜欢这个解释,你可以用谷歌找到其他的。)如果你有m大小为n的树,这就是时间O(nm) 交叉后缀树是一个并行遍历它们的问题,只有当您可以在所有树中走得更远时才能走
n
字符串(n>=2和nn;
对于(i=1;i>a[i];
if(a[i].length()对于(left=0;(unsigned)left来说,答案是分别构建所有字符串的后缀树,然后将它们相交。后缀树就像一个trie,同时包含一个字符串的所有后缀 为固定字母表建立后缀树是
O(n)
with。(如果你不喜欢这个解释,你可以用谷歌找到其他的。)如果你有m
大小为n
的树,这就是时间O(nm)
交叉后缀树是一个并行遍历它们的问题,只有当您可以在所有树中走得更远时才能走得更远。如果您有大小为n
的m
树,则此操作可以在不超过O(nm)
的时间内完成
这个算法的总时间是timeO(nm)
。如果只读取字符串是timeO(nm)
,那么你就没有比这更好的了
添加少量细节,假设您的后缀树是以每个节点一个字符的形式编写的。因此,每个节点只是一个字典,其键是字符,其值是树的其余部分。因此,在我们的示例中,对于字符串
ABABA
,处的图表将变成类似的数据结构(见下文)这个:
{
'A': {
'B': {
'': None,
'A': {
'B': {
'': None
}
}
}
},
'B': {
'': None
'A': {
'B': {
'': None
}
}
}
}
同样地,BABA
也会变成:
{
'A': {
'': None
'B': {
'A': {
'': None
}
}
},
'B': {
'A': {
'': None,
'B': {
'A': {
'': None
}
}
}
}
}
对于如下所示的数据结构,比较它们的朴素Python如下所示:
def tree_intersection_depth (trees):
best_depth = 0
for (char, deeper) in trees[0].items():
if deeper is None:
continue
failed = False
deepers = [deeper]
for tree in trees[1:]:
if char in tree:
deepers.append(tree[char])
else:
failed = True
break
if failed:
continue
depth = 1 + tree_intersection_depth(deepers)
if best_depth < depth:
best_depth = depth
return best_depth
现在我们可以看到,为了获得承诺的性能,缺少了一个步骤。问题是,虽然树的大小是
O(n)
,但在搜索它时,我们可能会访问O(n^2)
substring。在您的情况下,您不必担心这一点,因为substring的深度保证不会超过60。但在完全通用的情况下,您需要添加memorization,以便在递归导致比较以前看到的数据结构时,立即返回旧答案,而不是新答案一个(在Python中,你将使用<代码> ID-)(/Cuff>方法)将对象的地址与之前看到的对象进行比较。在C++中,有一组指针元组用于相同的目的。答案是分别构建所有字符串的后缀树,然后将它们相交。后缀树就像一个trie,同时包含一个字符串的所有后缀
为固定字母表建立后缀树是O(n)
with。(如果你不喜欢这个解释,你可以用谷歌找到其他的。)如果你有m
大小为n
的树,这就是时间O(nm)
交叉后缀树是一个并行遍历它们的问题,只有当您可以在所有树中走得更远时才能走得更远。如果您有大小为n
的m
树,则此操作可以在不超过O(nm)
的时间内完成
这个算法的总时间是timeO(nm)
。如果只读取字符串是timeO(nm)
,那么你就没有比这更好的了
添加少量细节,假设您的后缀树是以每个节点一个字符的形式编写的。因此,每个节点只是一个字典,其键是字符,其值是树的其余部分。因此,在我们的示例中,对于字符串
ABABA
,处的图表将变成类似的数据结构(见下文)这个:
{
'A': {
'B': {
'': None,
'A': {
'B': {
'': None
}
}
}
},
'B': {
'': None
'A': {
'B': {
'': None
}
}
}
}
同样地,BABA
也会变成:
{
'A': {
'': None
'B': {
'A': {
'': None
}
}
},
'B': {
'A': {
'': None,
'B': {
'A': {
'': None
}
}
}
}
}
对于如下所示的数据结构,比较它们的朴素Python如下所示:
def tree_intersection_depth (trees):
best_depth = 0
for (char, deeper) in trees[0].items():
if deeper is None:
continue
failed = False
deepers = [deeper]
for tree in trees[1:]:
if char in tree:
deepers.append(tree[char])
else:
failed = True
break
if failed:
continue
depth = 1 + tree_intersection_depth(deepers)
if best_depth < depth:
best_depth = depth
return best_depth
现在我们可以看到,为了获得承诺的性能,缺少了一个步骤。问题是,虽然树的大小是
O(n)
,但在搜索它时,我们可能会访问O(n^2)
substring。在您的情况下,您不必担心这一点,因为substring的深度保证不会超过60。但在完全通用的情况下,您需要添加memorization,以便在递归导致比较以前看到的数据结构时,立即返回旧答案,而不是新答案一个(在Python中,你将使用<代码> Id())/>代码>方法将对象的地址与你以前看到的那些比较。在C++中,有一组指针元组用于相同的目的。)/P>快速浏览一下,你的代码有{代码>{{}}},代码看起来大致是O(LGN ^ 2)。这个问题在O(n)附近有一个非常有效的解决方案。你应该看到,这是一个经典的算法problem@user3386109你说得对,我没有检查就输入了。这个例子的结果确实是5。对不起。@138好吧,这就是我使用的算法,KMP(你链接的那个)。但这不仅仅是搜索和检查。我必须在N个字符串之间找到最长的公共子字符串,因此要做的工作很多。第一个“for”设置当前模式(第一个字符串)的长度;第二个“for”选择当前模式(第一个字符串)的位置开始。我这样做是为了获得实际模式并构建“lps[]”数组。第三个“for”检查当前模式(第一个字符串)是否与所有其他字符串(从2到n)匹配。我不知道如何缩短时间。我认为这可以通过一个。使用最短的字符串来构建trie。然后处理其他字符串,标记已访问的节点,但不添加任何新节点。最后,遍历trie。所有字符串访问的最深节点的深度就是答案。@user3386109,无需记忆,比较后缀树的成本与比较尝试的成本类似。通过记忆,它的速度要快得多。后缀