找到子序列,一旦重复,生成给定序列

时间:2015-09-17 12:56:16

标签: algorithm data-structures big-o

给定一个大小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分钟的索引。

3 个答案:

答案 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);
}