我有一系列值,我想知道它是否包含某个最小长度的重复子序列。例如:
1, 2, 3, 4, 5, 100, 99, 101, 3, 4, 5, 100, 44, 99, 101
包含子序列3, 4, 5, 100
两次。它还包含两次子序列99, 101
,但是这个子序列只需要关注两个。
是否有一种有效的算法来检查这种子序列的存在?我对序列的位置并不特别感兴趣(尽管这对验证有帮助),我主要只是对真/假答案感兴趣,给出一个序列和最小子序列长度。
到目前为止,我唯一的方法是强力搜索它:对于序列中的每个项目,找到项目发生的所有其他位置(已经在O(N ^ 2)),然后向前走一步来自每个位置的时间,看看下一个项目是否匹配,并继续前进,直到找到不匹配或找到足够长度的匹配子序列。
我有另一个想法,但却未能发展成实际的方法是构建一个包含所有序列的树,这样每个数字都是一个节点,并且它的前面有一个数字的子节点,不管怎样节点恰好已经在树中。
答案 0 :(得分:4)
O(k)
的任何值都有k
个解决方案(N
- 整个序列的长度)。
解决方案#1:
为输入序列构建一个后缀树(使用Ukkonen算法)。
在具有两个或更多子节点的节点上迭代并检查其中是否至少有一个有深度>= N
。
解决方案#2:为输入序列构建后缀自动机。
迭代右上下文包含至少两个不同字符串的所有状态,并检查这些节点中是否至少有一个具有距离{ {1}}来自自动机的初始状态。
解决方案#3:
也可以使用后缀数组和最长公共前缀技术(为输入序列构建后缀数组,计算最长的公共前缀数组,检查是否存在一对相邻的公共前缀长度至少为>= N
)的前缀。
假设字母大小不变(字母表由输入序列的所有元素组成),这些解决方案的时间复杂度为N
。
如果不是这种情况,仍然可以获得O(k)
最坏情况时间复杂度(通过将所有转换存储在树中或O(k log k)
中的自动机中)或平均map
使用O(k)
。
P.S我在这里可以互换地使用术语hashmap
和string
。
答案 1 :(得分:1)
如果你只关心长度正好为N的子序列(例如,如果只是想检查没有重复),那么就有一个二次解决方案:对每个子序列使用KMP algorithm。
假设整个序列中有k个元素。
对于长度为N(O(k)的每个子序列):
因此,假设N <&lt; k,整个算法确实是O(k ^ 2)。
答案 2 :(得分:0)
由于您的列表无序,您将不得不至少访问一次每个项目。
我在想的是,您首先浏览列表并创建一个字典,其中将数字作为键存储,并将其显示在序列中的所有索引中。像:
Key: Indices
1: 0
2: 1
3: 2, 8
....
如果数字1出现在索引0处,数字2出现在索引1处,数字3出现在索引2和8处,依此类推。
创建后,您可以浏览字典键并开始将其与其他位置的序列进行比较。这可以节省一些蛮力,因为您不必每次都通过初始序列重新访问每个数字。