我有一个矩阵6000x20,包含的数字范围是1-80。我需要找到出现在该矩阵中的所有sextuplet。我需要最有效,最快速的解决方案。 我目前的解决方案是通过以下步骤: 1.我从矩阵中取第一行并生成所有六个对子(一行38600) 2.我将每个sextuple与其他5999行进行比较并计算它们 我把它们写进了一个文件,因为我的记忆很快就满了 4.我采取第二行并生成所有sextuplets,我再次执行所有步骤
这个算法非常糟糕并且我意识到它因为我有38600X6000比较和可能的文件写入,并且我有很多重复的sextuplets。但我不知道因为我不能使用那么大的变量。
我需要一个算法解决方案,所以我可以用matlab / java / c ++ / python
编写它答案 0 :(得分:1)
由于值的范围为1-80,因此可能的六胞胎总数“仅”超过3亿(准确地说是300,500,200)。由于矩阵中只有6000行,因此任何sextuplet的最大计数为6000,因此计数将轻松适合两个字节的整数(uint16_t
,假设存在于C ++实现中)。三亿个双字节整数总共600兆字节,你可能已经有了它。
因此,一个简单的算法是创建计数向量,初始化为零,然后迭代矩阵中的所有行;对于每一行,迭代38,760个sextuplet,并为每个sextuplet增加相应的计数。
技巧是弄清楚计数向量中的哪个元素对应于给定的六个数字集合。实际上,只要sextuplet中的数字从最小到最大,这并不太难。 (这不是限制,因为你需要对sextuplet有一些规范的顺序,按顺序排序是一个简单的规范排序。)
要了解如何生成索引,请考虑如何(假设)枚举集合{1..80}中所有300,500,200个六个整数的组合。首先,我们枚举以1开头的组合,并从集合{2..80}继续五个整数。然后,我们枚举以2开头的组合,并从集合{3..80}继续五个整数。然后,我们枚举以3开始的组合,并从集合{4..80}继续五个整数。等等。在每个起始点的枚举中,我们递归地应用相同的算法。
现在,让我们把这个枚举放在头上。假设我们有一些sextuplet {a,b,c,d,e,f}
。让我们问一下,在那个sextuplet之后有多少个sextup?
首先,所有以大于a
的值开头的sextuplet。由于sextuplet是有序的,如果一个sextuplet以大于a
的值开头,那么它的所有值都大于a
,这意味着它是来自set {{的六个值的某种组合。 1}},其中有 80-a C 6 。
然后,所有的sextuplet都以{a+1..80}
开头,并继续使用第一个值大于a
的五元组。通过上述相同的逻辑,这些六胞胎的数量是 80-b C 5 。
然后,所有的sextuplet都以b
开头,并继续使用第一个值大于a,b
的四重奏:总共 80-c ç<子> 4 子>
等
因此c
之后的sextuplet总数恰好是:
<子> 80-A 子> C <子> 6 子> + <子> 80-B 子> C <子> 5 子> + <子> 80-C < /子> C <子> 4 子> + <子> 80 d 子> C <子> 3 子> + <子> 80-E 子> C <子> 2 子> + <子> 80-F 子> C <子> 1 子>
上述等式的有趣之处在于六个变量之间没有相互作用。我们可以通过为 80-x C i 的值创建六个查找表来计算值,其中x的值从1到80,i的值从1到6然后我们可以通过只进行六次查找并将这些值加在一起来计算任何sextuplet的(逆)索引。 (如果我们需要,我们可以从组合总数中减去反向索引来获得前向索引。但在这种情况下,我们所需要的只是从组合到整数的双射,并且反向索引将正常工作。)< / p>
在算法结束时,有必要将计数索引转回sextuplets。这可以通过执行一系列二进制搜索使用相同的查找表来完成:首先,通过二进制搜索在i == 6的查找表中找到{a,b,c,d,e,f}
的值,然后减去相应的索引并继续在查找表中搜索i == 5等的余数(实际上,由于查找表很小,可能会发现线性搜索比二进制搜索更快。它可能没有多大区别。 )