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()=1;len--){
对于(left=0;(unsigned)left来说,答案是分别构建所有字符串的后缀树,然后将它们相交。后缀树就像一个trie,同时包含一个字符串的所有后缀

为固定字母表建立后缀树是
O(n)
with。(如果你不喜欢这个解释,你可以用谷歌找到其他的。)如果你有
m
大小为
n
的树,这就是时间
O(nm)

交叉后缀树是一个并行遍历它们的问题,只有当您可以在所有树中走得更远时才能走得更远。如果您有大小为
n
m
树,则此操作可以在不超过
O(nm)
的时间内完成

这个算法的总时间是time
O(nm)
。如果只读取字符串是time
O(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)
的时间内完成

这个算法的总时间是time
O(nm)
。如果只读取字符串是time
O(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,无需记忆,比较后缀树的成本与比较尝试的成本类似。通过记忆,它的速度要快得多。后缀