String 最短不常用子字符串:一个字符串的最短子字符串,它不是另一个字符串的子字符串

String 最短不常用子字符串:一个字符串的最短子字符串,它不是另一个字符串的子字符串,string,algorithm,suffix-array,String,Algorithm,Suffix Array,我们需要在两个字符串之间找到最短的不常用子字符串 i、 e.如果我们有两个字符串a和b,那么我们需要找到a的最短子串的长度,它不是b的子串 如何使用后缀数组解决这个问题 要以不超过n*lg(n)的复杂度求解,这可以在O(n)时间内用 在O(N)时间内构造广义后缀树之后,需要执行广度优先搜索,并找到不属于两个字符串的第一个节点。从根节点到该节点的路径给出了最短的子字符串 同样的事情也可以在O(N)时间内使用两个输入字符串的广义后缀数组来完成 与一起构造通用后缀数组(或稍后从后缀数组构造LCP数组

我们需要在两个字符串之间找到最短的不常用子字符串 i、 e.如果我们有两个字符串
a
b
,那么我们需要找到
a
的最短子串的长度,它不是
b
的子串

如何使用后缀数组解决这个问题

要以不超过n*lg(n)

的复杂度求解,这可以在O(n)时间内用

在O(N)时间内构造广义后缀树之后,需要执行广度优先搜索,并找到不属于两个字符串的第一个节点。从根节点到该节点的路径给出了最短的子字符串


同样的事情也可以在O(N)时间内使用两个输入字符串的广义后缀数组来完成


与一起构造通用后缀数组(或稍后从后缀数组构造LCP数组)。添加单个零元素作为LCP数组的前缀;添加另一个零元素作为后缀。查找一对最小LCP项,以使这些项仅分隔一个字符串的后缀。这意味着您需要对LCP数组执行线性扫描,提取两个最小值,但每次看到不同字符串的后缀或看到属于两个字符串的后缀时,将两个最小值重置为无穷大。这些对中最好的一对中较大的元素(对中较大的元素具有最小值)给出了最短的不寻常子串的长度。这是因为这对最小值分隔了第一个节点(最接近根节点)的所有子节点,而不是属于相应后缀树中的两个字符串。

为什么要用零填充LCP?如果我们一直扫描LCP的两个最小值,这仍然是O(n)?对不起,我问了这么多问题,你能不能也发一个例子?@ChrisZhang:用零填充不是绝对必要的。它只允许避免处理数组开始/结束的特殊情况。是的,它仍然是O(n);将其与在数组中找到2个最小值的情况进行比较,将每个数组元素插入到大小为2的最大堆中。无法创建足够简单的示例,抱歉。也许这篇论文会对你有所帮助。它解释了如何将几乎所有后缀树算法转换为SA算法。回答此问题时不知道。使用广义后缀树的解决方案是不正确的,因为在后缀树中,边可以是任意长度的(可能使用后缀树)。在广度优先搜索中查找非共享节点时(实际上,我认为深度优先搜索同样有效),候选解决方案是到最后一个共享节点的路径加上新找到的边的第一个字符。可以将此长度与以前的最短结果进行比较,如果是较短的解决方案,则将其替换。(如果当前最短子串的长度为1,我们可以停止搜索。)@uli_1973:实际上这里需要的是到任何非共享节点的单源最短路径。这完全可以通过检查每个树节点并选择距离根最短的节点来实现。但更自然的算法是使用BFS,并在发现非共享节点时立即停止。当然,这个BFS应该推广到后缀树上:普通队列应该被优先级队列取代。(可能最好不要将其命名为“广义BFS”,而应命名为“简化的Dijkstra算法”)。在CS(较新版本)上可能也是如此: