如何检测是否存在重复模式

时间:2014-10-24 13:56:19

标签: algorithm pattern-matching pseudocode

我的问题不是语言特定的...我可能会用C#或Python实现它,除非有一种语言的特定功能可以帮助我获得我想要的东西。

有没有人知道的某种算法可以帮助我确定数字列表是否包含重复模式?

假设我有几个数字列表......

[12, 4, 5, 7, 1, 2]
[1, 2, 3, 1, 2, 3, 1, 2, 3]
[1, 1, 1, 1, 1, 1]
[ 1, 2, 4, 12, 13, 1, 2, 4, 12, 13]

我需要检测每个列表中是否有重复模式...例如,列表1返回false,但是列表2,3和4返回true。

我在考虑可能会计算列表中出现的每个值,如果val 1 == val 2 == val n ...那么就可以了。有更好的想法吗?

6 个答案:

答案 0 :(得分:4)

您想要查看信号的自相关。自相关基本上是信号与自身的卷积。当您迭代地将一个信号滑过另一个信号并且存在重复模式时,输出将强烈共振。

答案 1 :(得分:3)

第二和第四个字符串是周期性的;我将假设您正在寻找一种用于检测周期性字符串的算法。大多数快速字符串匹配算法需要查找字符串周期以计算其移位规则。

例如,

Knuth-Morris-Pratt的预处理为模式P的每个前缀P [0..k]计算最长的适当后缀P [s]的长度SP [k]。 P [0..k]的.k]与前缀P [0 ..(ks)]完全匹配。如果SP [k]< k / 2,那么P [0..k]是非周期性的;否则,它是一个字符串的前缀,周期为k - SP [k]。

答案 2 :(得分:2)

一种选择是查看压缩算法,其中一些依赖于查找重复模式并将其替换为另一个符号。在您的情况下,您只需要标识模式的部分。您可能会发现它类似于您已经描述过的方法

答案 3 :(得分:1)

假设您的“重复模式”总是完整重复,就像您的示例数据所示,您可以将您的数组视为一堆长度相等的重复数组。含义:

[1, 2, 3, 1, 2, 3, 1, 2, 3][1, 2, 3]重复三次相同。

这意味着您可以检查数组中的每个x值是否彼此相等。所以: array[0] == array[3] == array[6]
array[1] == array[4] == array[7]
array[2] == array[5] == array[8]

由于你不知道重复模式的长度,你只需要尝试所有可能的长度,直到找到一个模式或用尽可能更短的数组。我确信有一些优化可以添加到下面,但它可以工作(假设我正确地理解了这个问题)。

static void Main(string[] args)
{
    int[] array1 = {12, 4, 5, 7, 1, 2};
    int[] array2 = {1, 2, 3, 1, 2, 3, 1, 2, 3};
    int[] array3 = {1, 1, 1, 1, 1, 1 };
    int[] array4 = {1, 2, 4, 12, 13, 1, 2, 4, 12, 13 };

    Console.WriteLine(splitMethod(array1));
    Console.WriteLine(splitMethod(array2));
    Console.WriteLine(splitMethod(array3));
    Console.WriteLine(splitMethod(array4));

    Console.ReadLine();
}

static bool splitMethod(int[] array)
{
    for(int patternLength = 1; patternLength <= array.Length/2; patternLength++)
    {
        // if the pattern length doesn't divide the length of the array evenly,
        // then we can't have a pattern of that length.
        if(array.Length % patternLength != 0)
        {
            continue;
        }

        // To check if every x value is equal, we need to give a start index
        // To begin our comparisons at.
        // We'll start at index 0 and check it against 0+x, 0+x+x, 0+x+x+x, etc.
        // Then we'll use index 1 and check it against 1+x, 1+x+x, 1+x+x+x, etc.
        // Then... etc.
        // If we find that every x value starting at a given start index aren't
        // equal, then we'll continue to the next pattern length.
        // We'll assume our patternLength will produce a pattern and let
        // our test determines if we don't have a pattern.
        bool foundPattern = true;
        for (int startIndex = 0; startIndex < patternLength; startIndex++)
        {
            if (!everyXValueEqual(array, patternLength, startIndex))
            {
                foundPattern = false;
                break;
            }
        }

        if (foundPattern)
        {
            return true;
        }
    }
    return false;
}

static bool everyXValueEqual(int[] array, int x, int startIndex)
{
    // if the next index we want to compare against is outside the bounds of the array
    // we've done all the matching we can for a pattern of length x.
    if (startIndex+x > array.Length-1)
        return true;

    // if the value at starIndex equals the value at startIndex + x
    // we can go on to test values at startIndex + x and startIndex + x + x
    if (array[startIndex] == array[startIndex + x])
        return everyXValueEqual(array, x, startIndex + x);

    return false;
}

答案 4 :(得分:1)

由于您正在寻找重复的模式,因此可以将数组强制转换为字符串并对其运行正则表达式。这是我的第二个答案,我只是在这里玩。

    static Regex regex = new Regex(@"^(?<main>(?<v>;\d+)+?)(\k<main>)+$", RegexOptions.Compiled);
    static bool regexMethod(int[] array)
    {
        string a = ";" + string.Join(";", array);
        return regex.IsMatch(a);
    }

正则表达式是

  1. (?<v>;\d+) - 一个名为&#34; v&#34;它匹配分号(在这种情况下是分隔符)和1个或多个数字

  2. (?<main>(?<v>;\d+)+?) - 名为&#34; main&#34;匹配&#34; v&#34;组合1次或更多次,但满足正则表达式的次数最少。

  3. (\k<main>)+ - 匹配&#34; main&#34;组匹配1次或更多次

  4. ^ ... $ - 这些将模式的两端固定在字符串的末尾。

答案 5 :(得分:0)

简单模式识别是压缩算法的任务。根据输入的类型和您正在寻找的模式类型,所选择的算法可能会有很大不同 - 只要考虑任何文件是一个字节数组,并且对于各种类型的数据有许多类型的压缩。无损压缩找到重复和有损压缩的精确模式 - 近似受某些“真实世界”考虑限制的近似模式。

在您的情况下,您可以应用伪zip压缩,开始填写遇到的序列列表

这是一个伪建议:

//C#-based pseudo code

int[] input = GetInputData();
var encounters = new Dictionary<ItemCount<int[],int>>();// the string and the number of times it's found

int from = 0;
for(int to=0; to<input.Length; i++){ 
  for (int j = from; j<=i; j++){ // for each substring between 'from' and 'i'
    if (encounters.ContainsKey(input.SubArray(j,i)){
      if (j==from) from++;                  // if the entire substring already exists - move the starting point
      encounters[input.SubArray(j,i)] += 1; // increase the count where the substring already exists
    } else {
     // consider: if (MeetsSomeMinimumRequirements(input.SubArray(j,i))
      encounters.Add(input.SubArray(j,i),1); //add a new pattern
    }
  }
}
Output(encounters.Where(itemValue => itemValue.Value>1); // show the patterns found more than once

我没有调试上面的示例,因此只能将其作为起点。核心思想是你有一个encounters列表,其中收集和计算了各种子字符串,最常见的是最终Value

您可以通过存储子字符串的某些函数而不是整个子字符串来更改上述算法,或者添加一些最低要求,例如最小长度等。选项太多,在帖子中无法完成讨论。