是否有任何算法可以在某些模式中对数组进行分类?

Posted

技术标签:

【中文标题】是否有任何算法可以在某些模式中对数组进行分类?【英文标题】:Are there any algorithms to categorize an array among certain patterns? 【发布时间】:2012-12-03 09:47:41 【问题描述】:

对于数组长度为 5 的简单问题(实际上数组长度可能为 20..)

我有一组预定义模式,例如 AAAAB、AAABA、BAABC、BCAAA、...每个模式与输入数组的长度相同。我需要一个函数,它将任何整数数组作为输入,并返回它匹配的 all 模式。 (一个数组可能匹配几个模式)尽可能快。

A”表示模式中A位置上的所有数字都相等。例如。 AAAAA 仅表示所有数字都相等,1, 1, 1, 1, 1 匹配 AAAAA

B”表示B位置的数字不等于A位置的数字。(即不是A的数字的通配符)表示的数字B 不必相等。例如。 ABBAA 表示第 1、第 4、第 5 个数字等于 x,而第 2、第 3 个数字不等于 x。 2, 3, 4, 2, 2 匹配 ABBAA

C”表示该位置可以是任意数字(即数字的通配符)。 1, 2, 3, 5, 1 匹配 ACBBA1, 1, 3, 5, 1 也匹配 ACBBA

我正在寻找一种有效的(就比较数而言)算法。它不必是最优的,但不应该是最优的。我觉得它有点像决策树......

一个非常简单但效率低的方法如下:

尝试将每个模式与输入进行匹配。对 a, b, c, d, eAABCA。它检查是否(a=b=e && a!=c)

如果pattern的个数是n,pattern/array的长度是m,那么复杂度大约是O(n* m)

更新:

请随时为问题提出更好的措辞,因为我不知道如何使问题简单易懂且不会造成混淆。

理想的算法需要某种准备,例如将模式集转换为决策树。这样对于某些特殊模式集,预处理之后的复杂性可以达到 O(log n * log m) 之类的东西。(只是猜测)

一些可能有用的数字:预定义模式集的大小大约为 30。要匹配的输入数组的数量约为 1000 万。

假设 AAAAAAAAAC 都在预定义的模式集中。那么如果 AAAAAA 匹配,AAAAC 也匹配。我正在寻找一种可以识别的算法。

更新 2

@Gareth Rees 的回答给出了一个 O(n) 解决方案,但假设没有很多“C”。 (否则存储量很大,很多不必要的比较)

我也欢迎任何关于如何处理有许多“C”的情况的想法,例如,对于长度为 20 的输入数组,至少有 10 个“C” "s 用于每个预定义的模式。

【问题讨论】:

2, 3, 4, 2, 2 匹配 ABBAA。但是2, 3, 3, 2, 2 匹配 ABBAA 吗? @AlexFilipovici 是的,他们都这样做 A 是否存在于所有可用的模式中? @AlexFilipovici 好吧,我会说是的,否则,没有 A 的模式会使 B 毫无意义,所以它最终会得到所有的 C,这是微不足道的(匹配所有内容) 对于长度为n的给定数组,有n * Math.Pow(2, n - 1)可能的模式。 【参考方案1】:

这是一个将 O(2n) 准备和存储换成 O(n)-ish 运行时的想法。如果你的数组不超过你机器的字长(你暗示 20 是典型的大小),或者如果模式中没有太多的 C 出现,这个想法可能对你有用. (如果这两个条件都不满足,请避免!)

    (准备步骤,完成一次。)创建字典d,将数字映射到模式集。对于每个模式 p,以及该模式中出现的 C 的每个子集 S,设 n 为具有对应于模式中每个 A 以及 S 中每次出现 C 的设置位的数字。将 p 添加到模式集 d[n]。

    (每次需要将新数组与模式进行匹配时,都会执行剩余步骤。)创建一个字典e,将数字映射到数字。

    j 遍历数组的索引,并且对于每个 j

      i 为数组中的第 j 个整数。

      如果 i 不在字典 e 中,则设置 e[i] = 0 .

      设置 e[i] = e[i] + 2ℓ − j − 1 其中ℓ是数组的长度。

    现在 e 的键是数组中不同的数字 i,而值 e[i ] 有一个设置位,对应于数组中每次出现的 i。对于在字典 d 中找到的每个值 e[i],集合 d 中的所有模式[e[i]] 匹配数组。

(注意:在实践中,您会反过来构建位集,并在步骤 3.3 使用 2j 而不是 2ℓ - j - 1,但为了清楚起见,我以这种方式描述了算法。)

这是一个例子。假设我们有模式 AABBAACBBA。在预处理步骤中AABBA变成数字25(二进制11001),ACBBA变成数字25(二进制11001)和17(二进制10001),对于模式中 C 出现的两个可能子集。所以字典 d 看起来像这样:

17 → ACBBA 25 → AABBA, ACBBA

处理完数组 1, 2, 3, 5, 1 我们有 e = 1 → 17, 2 → 8, 3 → 4, 5 → 2。值 e[1] = 17 在 d 中找到,因此该输入匹配模式 ACBBA

处理完数组 1, 1, 2, 3, 1 我们有 e = 1 → 25, 2 → 4, 3 → 2。值 e[1] = 25 在 d 中找到,因此此输入匹配模式 AABBAACBBA .

【讨论】:

BAABC 与 ABBAC 不同,因为“B 所代表的数字不必相等” @colinfang:谢谢:我应该更仔细地阅读。这是一个不同的想法。 我对算法的描述更加明确。我希望我们最终会到达那里。 谢谢你,我终于明白了。 @colinfang:关于您的“更新 2”,如果您有 30 个模式,每个模式出现 10 次 C,那么字典 d 包含多达 30,720 个键。与 10,000,000 个数组相比,这似乎不是很多。此外,“许多不必要的比较”似乎是错误的:每个输入数组中的每个唯一数字只有一个哈希表查找:很难看到你能做得更好。【参考方案2】:

获取模式中第一个A 的索引,获取该位置的值,然后遍历这些位置。

要检查数组array是否与字符串pattern中的模式匹配,结果在布尔值match中:

int index = pattern.IndexOf('A');
int value = array[index];
bool match = true;
for (int i = 0; i < array.Length; i++) 
  if (pattern[i] != 'C' && i != index) 
    if ((pattern[i] == 'A') != (array[i] == value)) 
      match = false;
      break;
    
  

【讨论】:

嗯,我错过了什么,这怎么不是 O(N*M)? @Woot4Moo 是 O(N),因为最多有 2 次顺序线性扫描(第 1 次 - IndexOf,第 2 次 - for 循环)。所以它是:O(N) + O(M) = O(N)。 贴出的代码是O(N),但由于有M种不同的模式,它必须运行M次。这个解是 O(N*M)。 由于pattern的长度与数组的长度相同,所以编码为O(N+N),与O(N)相同。循环遍历这些模式可以得到 O(N*M)。 它与我的“直截了​​当但效率低下”的方式有何不同? O(N * M) 效率不高。比如说,如果 AAAAA 和 AAAAC 都在预定义的模式集中。那么如果 AAAAA 匹配,则 AAAAC 也匹配。我正在寻找一种可以识别的算法。

以上是关于是否有任何算法可以在某些模式中对数组进行分类?的主要内容,如果未能解决你的问题,请参考以下文章

我如何在ML中对评论进行分类?

如何在 C# 中对二维(矩形)数组进行排序?

在matlab中对单元格数组进行分类

在android中对图像进行手绘裁剪

excel中对数据进行分类求和

在 SQL 中对有序数据中的子集进行分组