在一大堆数字中找到最常见的六胞胎
Finding most common sextuplets in a huge set of numbers
我有一个矩阵6000x20,包含的数字范围从1-80。我需要找到该矩阵中出现的所有六胞胎。我需要最有效、最快的解决方案。我目前的解决方案是以下步骤:1.我从矩阵中取第一行并生成所有六胞胎(一行38600(2.我将六行中的每一行与其他5999行进行比较并计算它们3.我将它们写入文件,因为我的内存很快就会填满4.我采取第二行并生成所有六胞胎,然后再次执行所有步骤
这个算法非常糟糕,我知道它,因为我有 38600X6000 的比较和可能的文件写入,而且我有很多六胞胎重复。但我无法知道,因为我不能使用这种大小的变量。
我需要一个算法解决方案,这样我就可以用matlab/java/c++/python编写它
由于值的范围从1到80,可能的六胞胎总数"仅"超过3亿(准确地说是300,500,200(。由于矩阵中只有 6000 行,因此任何六胞胎的最大计数为 6000,因此计数将舒适地适合一个双字节整数(uint16_t
,假设存在于您的C++实现中(。三亿个双字节整数总共 600 兆字节,您可能已经可用。
因此,一个简单的算法是创建计数向量,初始化为零,然后迭代矩阵中的所有行;对于每一行,迭代38,760个六胞胎,对于每个六胞胎,递增相应的计数。
诀窍是弄清楚计数向量中的哪个元素对应于给定的六个数字集。碰巧的是,只要六胞胎中的数字从小到大依次排列,这并不难。(这不是限制,因为您需要为六胞胎设置一些规范顺序,并且按顺序排序是一个简单的规范顺序。
若要了解如何生成索引,请考虑如何(假设(枚举集合 {1..80} 中六个整数的所有 300,500,200 个组合。首先,我们枚举以 1 开头的组合,然后继续从集合 {2..80} 中获取五个整数。然后,我们枚举以 2 开头的组合,并继续从集合 {3..80} 中获取五个整数。然后,我们枚举以 3 开头的组合,然后继续从集合 {4..80} 中获取五个整数。等等。在每个起点的枚举中,我们递归应用相同的算法。
现在,让我们把这个枚举颠倒过来。假设我们有一些六胞胎{a,b,c,d,e,f}
.让我们问一下,在那个六胞胎之后有多少个六胞胎?
首先,所有以大于
a
的值开头的六胞胎。由于六胞胎是有序的,如果一个六胞胎以大于a
的值开头,那么它的所有值都大于a
,这意味着它是集合{a+1..80}
中六个值的某种组合,其中有80-aC6。然后,有所有六胞胎,它们以
a
开头,然后以第一个值大于b
的五胞胎继续。根据上述逻辑的相同逻辑,这种六胞胎的数量为80-bC5。然后,有所有六胞胎,它们以
a,b
开始,然后是第一个值大于c
的四重奏:总共80-cC4等。
因此,{a,b,c,d,e,f}
之后的六胞胎总数精确地为:
80-aC6+80-b C5+80-cC 4+80-d C3+80-e C2+80-fC 1
上述等式的有趣之处在于,六个变量之间没有相互作用。我们可以通过为 80-x Ci 的值创建六个查找表来计算该值,为 x 的值从 1 到 80,i的值从 1 到 6。然后,我们可以通过进行六个查找并将值相加来计算任何六胞胎的(逆(索引。(如果需要,我们可以从组合总数中减去反索引以获得正向索引。但在这种情况下,我们所需要的只是从组合到整数的双射,逆索引就可以正常工作。
在算法结束时,有必要将计数指数重新转换为六胞胎。这可以通过执行一系列二叉搜索来使用相同的查找表来完成:首先,通过在查找表中查找 i==6 的二叉搜索来查找 a
的值,然后减去相应的索引并继续在查找表中搜索 i==5 的余数,依此类推(实际上,由于查找表很小, 事实证明,线性搜索可能比二叉搜索更快。这可能没有太大区别。
- 使用strcpy将char数组的元素复制到另一个数组
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 在 c++ 中拥有一组结构的正确方法是什么?
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何将三维尺寸不固定的三维阵列展平为一维阵列
- nlohmann-json将一个数组插入到另一个数组中
- 有没有一种方法可以在编译时获得作用域类名
- 为什么make_tie不是一件事
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- c++中O(n^(1/3))中一个数的除数的有效计数
- 一种在C++中读取TXT配置文件的简单方法
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 在调用接收数组的方法时,模板化数组大小是不是一种糟糕的做法
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 为什么我必须在C++中添加一个赋值符号来声明一个数组
- 我是否需要在下一次转移时将所有权*转移回转移队列
- 拥有具有相同名称的库的静态和动态版本是一种常见的做法
- 在一大堆数字中找到最常见的六胞胎