给定一个大小N
的序列,它是未知子序列的重复,你如何有效地找到子序列的大小M
?
例如:
input : 6651366513665136651366513 -> output : sequence of length 5 which is 66513
input : 11111111111111111111111111111 -> output : sequence of length 1 which is 1
input : 6651366513665136651366513665 -> output : sequence of length 5 which is 66513
N
不是M
的倍数,因为最后一个序列不必完整。例如,665
可以附加到第一个示例。天真的方式是:
假设子序列的大小为
x
,测试,如果不正确则增加x
然后重试或输出x
我仍在设计另一种解决方案,它没有O(N^2)
时间复杂度,如上所述。
注意:对于好奇的我正在解析需要从流分析构建索引的媒体文件,我发现索引遵循重复模式。我可以解析一分钟而不是解析2h
个文件,并猜测下一个1小时59分钟的索引。
答案 0 :(得分:4)
给定序列S
,要查找句点的长度,您只需在S
中找到第二次出现的S+S
。例如:
搜索
6651366513665136651366513
在
66513665136651366513665136651366513665136651366513
表示序列第二次出现在索引5
中。鉴于原始序列的长度= 25,您可以看到它重复5次。
您可以使用您想要的任何子串搜索算法,例如KMP保证了O(n)的复杂性。
答案 1 :(得分:1)
Niklas B 建议的Z algorithm是我发现问题的最佳匹配。实际上它被定义为:
Zi(P)
=从i > 0
开始的P的最长子串的长度 并匹配前缀P.
给定z算法,子序列的长度是满足(如果有)的索引k
:
z[k] = n - k
z[k] = max(z[i])
输入
std::vector<int> v = { 6, 6, 5, 1, 3, 6, 6, 5, 1, 3, 6, 6, 5, 1, 3, 6, 6, 5 };
z-indexes是
std::vector<int> z = { 0, 1, 0, 0, 0,13, 1, 0, 0, 0, 8, 1, 0, 0, 0, 3, 1, 0 };
和k = 5
答案 2 :(得分:0)
所以你的想法是从最小的子序列= 1开始,并且这个子序列中的当前索引= 0.然后你开始比较字符串中的每个字符。如果当前字符与当前最小子序列中的索引匹配,则增加当前索引子序列(%是在到达当前子序列大小的末尾后将其重置为零)。如果它们不匹配,则将窗口大小设置为当前索引+ 1,并将窗口内的当前索引重置为0,然后重新开始此过程。这在O(N)中运行。
public void getMinSubsequenceLength(String s){
int currentMinSubsequence=1;
int currentIndexInSubsequence = 0;
for(int i=1;i<s.length();i++){
if(s.charAt(i)!=s.charAt(currentIndexInSubsequence)){
currentMinSubsequence = i+1;
currentIndexInSubsequence = 0;
} else {
currentIndexInSubsequence = (currentIndexInSubsequence+1)%currentMinSubsequence;
}
}
System.out.println(currentMinSubsequence);
}