我有一个256位值的数组。该数组是巨大的(数百万条记录),但它很少被修改,它适合内存。对于给定的256位数,我想查找是否存在至少N位相等的记录。例如,10000和01111的0位相等,1000和1001的3位相等。总是N> 128,或者更确切地说,N> 140.我不需要找到一个特定的号码,我只需要查看列表中是否存在这样的号码。
是否有某种数据结构或某种索引可以某种方式加速搜索?
答案 0 :(得分:1)
要解决的算法是O(n)。您唯一的选择是循环遍历数组,直到找到与您的目标匹配的数字。
现在,我们如何找到两个数字是否匹配?最有效的方法是使用按位运算。例如,我编写了一个适用于64位长数字的代码:
int compare(long l1, long l2)
{
//Use xor to get what bits are the same
long xor = ~ (l1 ^ l2);
//count the number of bits with value = 1
int count = 0;
while(xor != 0)
{
//check if the right bit is 1, using & operator beetween our number and 0000001
if(xor & 1 > 0) count++;
//shift right the bits
xor = xor >> 1
}
return count;
}
根据您的256位数字的实现方式,可以调整此比较。
当您到达count >= N
时,优化可能是打破while循环。
您可以查看this question以查找更有效的方法来计算值为1
的位。
希望它有所帮助!
答案 1 :(得分:1)
我可能错了,但看起来您可以将数据索引为按位trie,对于您的情况,它与结构中的二叉树相同,但解释不同。这是插图(source):
为了简单起见,让我们考虑你的256位数字,就像256个数字的矢量一样(当然也是二进制数)。拥有如上所述的树,您可以通过向下走树并测试后续分支(“0”或“1”)是否存在,找到数据集中是否存在256步或更少的特定向量。像这样的东西(代码非常原始,但你应该知道):
def exists(node, v, i):
"""Checks if subvector of v starting from index i exists in
sub-tree defined by node
"""
if i == len(v):
return True
elif v[i] == 0 and node.left:
return exists(node.left, v, i + 1)
elif v[i] == 1 and node.right:
return exists(node.right, v, i + 1)
else:
return False
在每个步骤中,我们根据v
的当前值元素决定向左或向右分支的位置。但是您还需要处理多达K个不同的元素。好的,那么为什么不使用错误计数并处理两个分支?
def exists(node, v, i, err_left=K):
"""Checks if subvector of v starting from index i exists in
sub-tree defined by node with up to err_left errors.
"""
if i == len(v):
return True
elif v[i] == 0:
if node.left:
return exists(node.left, v, i + 1, err_count)
elif node.right:
return exists(node.left, v, i + 1, err_left - 1) # proceed, but decrease
# errors left
else:
return False
elif v[i] == 1:
if node.right:
return exists(node.right, v, i + 1, err_count)
elif node.left:
return exists(node.right, v, i + 1, err_left - 1) # proceed, but decrease
# errors left
else:
return False
else:
return False
此算法的运行时间在很大程度上取决于您的设置。在最坏的情况下(K = 256)它仍然是O(n)(你需要检查每个分支),但是这个时间随着K的减小而迅速下降(小K几乎为O(log n))。 K~128就在中间的某个地方。
您可能还需要重写功能,以便首先检查好日(无错误)方案(例如,如果您预计错误的数量平均很小)。
从某种意义上讲Trie压缩数据,但如果您遇到内存问题,请尝试使用表格表示而不是对象和指针。
最后,您可以将其与bloom filters结合使用,以过滤绝对不在集合中的数字,然后使用上面的树检查其余部分。