有效地测试一个列表是否是另一个列表的排列

时间:2012-06-01 22:46:23

标签: c arrays assembly permutation

我正在阅读http://comicjk.com/comic.php/906,其中列出了检查一个列表是否是另一个列表的排列的问题,并提出了两种解决方案。

'c brain'解决方案“你知道这些列表将总是包含四个数字,并且每个数字将小于256,所以我们可以将所有排列字节打包成32位整数......”

'python brain'解决方案是对两者进行排序,然后对它们进行比较,这似乎更为明显,但我对更有效(和低级别)的解决方案感兴趣。

我的初步方法是:

int permutations(int a[4], int b[4]){
  int A = a[0] | a[1]*1<<8 | a[2]*1<<16 | a[3]*1<<24;
  int B = b[0] | b[1]*1<<8 | b[2]*1<<16 | b[3]*1<<24;

  unsigned int c=0, i=0;

  for( i=0xFF; i>0; i<<=8 ){
      if( 
        A&i == B&0xFF ||
        A&i == B&0xFF00 ||
        A&i == B&0xFF0000 ||
        A&i == B&0xFF000000
      ) c |= i;
  }

  if( c == 0xFFFFFFFF )
    return 1;
  return 0;
}

但除非我能找到一个简单的方法将A&amp; i和B * 0xxxxxxxxx放在同一个字节(在我们正在查看的字节后删除任何尾随的0),否则这个工作无法工作。 像

这样的东西
(a&i>>al)>>ar == b(&j>>bl)>>br

其中al + ar == bl + br == 4并用于确定我们正在检查的字节。

另一种方法

评论框中有人说“在C中,为什么不简单地动态分配一段适当大小的内存并将其作为单个数字处理? 是的,它比使用int慢一点,但它也不限于包含四个或更少的元素或最大数量为256,并且仍然比排序更快(无论是在C还是Python中)......“< / p>

如果我们可以有一个长度大于最大数字的数组,那么我们可以设置适当的位并比较数组,但这会比较我们进行比较,除非我们可以将其视为一个比较c中有效的大量数据。

在x86(我刚开始学习)中,我们有SBC指令,所以我们可以减去每个部分,如果结果全部为零(我们可以用JNE / JNZ测试)它们是相等的。

据我所知,我们仍然需要做/ SBC和跳跃

实际问题

我想知道如何

  1. 字节打包
  2. 将整个列表视为一个大数字
  3. 可用于检查列表是否是另一个列表的排列(假设列表不超过4个项目且每个项目<256)

3 个答案:

答案 0 :(得分:2)

优化假设结果可能是“否”:计算每个列表的总和(或xor,或其他一些廉价的,关联的,可交换的运算符)。如果总和不同,答案是没有进一步测试。如果总和相同,则执行更昂贵的测试以获得明确的答案。

答案 1 :(得分:1)

我认为你只想要一个不受排列影响的哈希。添加作为一种方法提供。我在考虑一种与bloom过滤器兼容的方法,因此您可以使用它做更多的事情。

布隆过滤器可以处理任意长度的列表和任意大小的数字。它可用于查看列表是否具有与一组列表相同的排列。它可用于查看列表中是否存在元素。

布隆过滤器基本上是一个位数组。你只需要'或'组成你的列表的元素的位,以产生布隆过滤器。任何顺序中具有相同元素的列表都将设置相同的位。对于小型列表,您可以使用整数大小的数字来处理位数组:

unsigned char b = a1|a2|a3|a4; // where a1..n are items (8 bit numbers)

如果您有项目a1和带有bloom b的列表,并想知道a1是否在列表中:

fPossibleMatch = ((a1&b) == a1);

如果您有两个任意长度的列表,其中包含b1,b2,并且想知道b1中是否存在b1的所有项目:

fPossibleMatch = ((b1&b2) == b1);

如果你想知道具有相同元素数量的列表b1和b2是否是彼此的排列。

fPossibleMatch = (b1==b2);

要减少误报,请加宽布隆过滤器。如果我们使用64位bloom,我们可以使用这个任意选择的算法来扩展位:

unsigned long long b = (a1<<(a1&0x1F)) | (a2<<(a2&0x1F)) | (a3<<(a3&0x1F)) | a4<<(a4&0x1F);

我有一种感觉,我扩大绽放的算法并没有任何好处。它可能只是将所有位设置为糊状。其他人可能知道更好的方法。我想你明白了。

我认为这更好:

#define MUNGE(a) ((a)<<(((a)&7)<<3))
unsigned long long b = MUNGE(a1)|MUNGE(a2)|MUNGE(a3)|MUNGE(a4)

我不善于创造哈希。

您仍然需要仔细检查具有匹配的bloom过滤器的任何列表。随着列表长度和元素大小的增加,误报的数量也会增加。假阳性随着花朵大小的增加而减少。

答案 2 :(得分:1)

使用哈希表并遍历每个列表。这将提供一个需要O(n)时间和O(n)内存的解决方案。