广义后缀树遍历以查找最长的公共子字符串

Generalised suffix tree traversal to find longest common substring

本文关键字:字符串 查找 后缀 遍历      更新时间:2023-10-16

我正在使用后缀树。据我所知,我让 Ukkonen 的算法正确运行,以从任意数量的字符串构建通用后缀树。我现在正在尝试实现一种find_longest_common_substring()方法来做到这一点。为此,我知道我需要在树中的所有字符串之间找到最深的共享边缘(在字符方面具有深度,而不是边缘(,并且我已经努力了几天才能正确遍历。

现在我有以下C++。我将省略我的所有代码,但为了上下文,我将每个节点的边缘保留在一个名为outgoing_edges的unordered_map中,并且每个边缘都有一个整数向量,recorded_strings包含标识添加字符串的整数。边的child字段是它要去的节点,lr分别标识其最左边和最右边的索引。最后,current_string_number是树中的当前字符串数。

SuffixTree::Edge * SuffixTree::find_deepest_shared_edge(SuffixTree::Node * start, int current_length, int &longest) {
Edge * deepest_shared_edge = new Edge;
auto it = start->outgoing_edges.begin();
while (it != start->outgoing_edges.end()) {
if (it->second->recorded_strings.size() == current_string_number + 1) {
int edge_length = it->second->r - it->second->l + 1;
int path_length = current_length + edge_length;
find_deepest_shared_edge(it->second->child, path_length, longest);
if (path_length > longest) {
longest = path_length;
deepest_shared_edge = it->second;
}
}
it++;
}
return deepest_shared_edge;
}

据我所知,在尝试调试时,遍历运行基本正常,并正确记录路径长度并设置最长路径。然而,由于我不太明白的原因,在最内在的条件中,deepest_shared_edge有时似乎被更新到一个错误的边缘。我怀疑我可能不太明白it->second在整个递归过程中是如何更新的。然而,我不太确定如何解决这个问题。

我知道这个类似的问题,但这种方法似乎足够不同,我不太确定它在这里如何应用。

我主要是为了好玩和学习,所以我不一定需要工作代码来替换上述内容 - 伪代码或只是对我困惑的地方的任何解释也一样。

你对deepest_shared_edge的处理是错误的。 首先,您在函数开始时执行的分配是内存泄漏,因为您永远不会释放内存。 其次,递归调用的结果被忽略,因此它找到的任何最深的边缘都会丢失(尽管您更新了深度,但不会跟踪最深的边缘(。

要解决此问题,您应该将deepest_shared_edge作为引用参数传递(就像longest一样(,或者您可以将其初始化为nullptr,然后检查递归调用的返回值以获取nullptr并适当更新它。