给定一个按顺序排列的256个数字列表(0-255),我想表达这个列表中的128个数字子集。每个数字都将是唯一的,不重复。
如何以最紧凑的方式表达这个子集?
到目前为止,我想到的方法是使用一个长度为256的位数组,并将适当的索引设置为1。这种方法显然需要256位来表示128个值,但是否有不同的、更节省空间的方法呢?
谢谢!
给定一个按顺序排列的256个数字列表(0-255),我想表达这个列表中的128个数字子集。每个数字都将是唯一的,不重复。
如何以最紧凑的方式表达这个子集?
到目前为止,我想到的方法是使用一个长度为256的位数组,并将适当的索引设置为1。这种方法显然需要256位来表示128个值,但是否有不同的、更节省空间的方法呢?
谢谢!
在一个包含256个项目的集合中,从中选择128个元素且顺序不重要,有256! / (128! * (256 - 128)!)种独特的组合(关于组合请参见wiki)。
如果你计算这个数字并取以2为底的对数,你会发现它是251.6。这意味着你需要至少252位来表示从256个项目中选择128个项目的唯一选择。由于.NET无法表示位(只能表示整个字节),因此没有必要实际找出如何完成这个任务。
128是在这方面最糟糕的数字。如果你选择5个元素或者从256个项目中选择251个元素,那么可以用34位表示,并且尝试找到这种有效的表示方式是有用的。
由于您不关心子集的顺序,也不关心将每个元素恢复到原始数组中的位置,因此这只是产生数组的随机子集的情况,类似于从牌堆中抽取卡牌。
要从数组中获取唯一元素,您可以简单地对源数组进行洗牌,然后在前X个索引处取出若干元素:
int[] srcArray = Enumerable.Range(0, 256).ToArray();
Random r = new Random();
var subset = srcArray.OrderBy(i => r.Next()).Take(128).ToArray();
注意:我使用上述随机化方法是为了保持示例简洁。对于更强大的洗牌方法,我建议使用Fisher-Yates算法,如this post所述。