给定一个数字N
和一组由唯一元素组成的表格,我怎样才能找到每个表格中只出现偶数次数的N个条目的所有组合?
注意:实际上,我有几百个表,每个表包含大约一百万个条目,每个条目的数字介于0到2百万之间。而我正试图找到大约500个数字的集合 这就是为什么我在寻找一种有效的算法。
例如,给定N=4
和以下表格:
Table #1 #2 #3 #4 #5
,---. ,---. ,---. ,---. ,----.
| 0 | | 5 | | 7 | | 4 | | 9 |
| 1 | | 3 | | 6 | | 1 | | 7 |
| 9 | | 2 | | 4 | | 0 | | 11 |
| 2 | | 7 | | 3 | | 7 | | 10 |
| 8 | | 6 | | 9 | | 5 | | 2 |
| 5 | | 0 | | 0 | | 8 | | 12 |
'---' '---' '---' '---' '----'
要找到的解决方案是:
Solution table #1 #2 #3 #4 #5
-------- ------------------------------------------------
0, 2, 4, 10 : [0, 2] [0, 2] [0, 4] [0, 4] [2, 10]
0, 1, 2, 9 : [0, 1, 2, 9] [0, 2] [0, 9] [0, 1] [9, 2]
0, 2, 4, 11 : [0, 2] [0, 2] [0, 4] [0, 4] [2, 11]
0, 2, 4, 12 : [0, 2] [0, 2] [0, 4] [0, 4] [2, 12]
0, 2, 8, 9 : [0, 8, 2, 9] [0, 2] [0, 9] [0, 8] [9, 2]
1, 3, 6, 8 : [8, 1] [3, 6] [3, 6] [8, 1] []
1, 4, 9, 10 : [1, 9] [] [9, 4] [1, 4] [9, 10]
1, 4, 9, 11 : [1, 9] [] [9, 4] [1, 4] [9, 11]
1, 4, 9, 12 : [1, 9] [] [9, 4] [1, 4] [9, 12]
1, 8, 10, 11: [8, 1] [] [] [8, 1] [10, 11]
1, 8, 10, 12: [8, 1] [] [] [8, 1] [10, 12]
1, 8, 11, 12: [8, 1] [] [] [8, 1] [11, 12]
2, 3, 5, 7 : [2, 5] [2, 3, 5, 7] [3, 7] [5, 7] [2, 7]
2, 5, 6, 7 : [2, 5] [2, 5, 6, 7] [6, 7] [5, 7] [2, 7]
3, 6, 10, 11: [] [3, 6] [3, 6] [] [10, 11]
3, 6, 10, 12: [] [3, 6] [3, 6] [] [10, 12]
3, 6, 11, 12: [] [3, 6] [3, 6] [] [11, 12]
4, 8, 9, 10 : [8, 9] [] [9, 4] [8, 4] [9, 10]
4, 8, 9, 11 : [8, 9] [] [9, 4] [8, 4] [9, 11]
4, 8, 9, 12 : [8, 9] [] [9, 4] [8, 4] [9, 12]
我已经使用过这个python程序,但它是一个天真的实现,我不喜欢它的复杂性,它高于:
X = (
(0,1,9,2,8,5),
(5,3,2,7,6,0),
(7,6,4,3,9,0),
(4,1,0,7,5,8),
(9,7,11,10,2,12)
)
# find unique elements across all lists
ALL = tuple(set([l for i in range(len(X)) for l in X[i]]))
LEN = len(ALL)
def find_all():
Solutions = []
for i in range(0, LEN-3):
for j in range(i+1, LEN-2):
for k in range(j+1, LEN-1):
for l in range(k+1, LEN):
if count_even((ALL[i], ALL[j], ALL[k], ALL[l])):
Solutions.append([ALL[i], ALL[j], ALL[k], ALL[l]])
return Solutions
def count_even(values):
"""return True if some elements of `values` appear
an even number of times in every list"""
for List in X:
Accumulator = 0
for Value in values:
for Elem in List:
if Elem == Value:
Accumulator += 1
if Accumulator & 1 == 1:
return False
return True
for v in find_all():
print v
我对优化感兴趣的函数是find_all()
,因为它有太多的嵌套循环
也许使用高斯消除或树或任何其他众所周知的算法可以做些什么。
任何帮助都非常感激。
答案 0 :(得分:0)
(抱歉无法发表评论)
作为一项小改进,您可以预先计算和存储(例如,在散列图中,或者在数组中,如果值是从0到已知I_MAX的整数),每个表中每个元素的出现次数(时间O( N * N))
然后:
构建N个元素的所有集合O(n ^ N)
,每个表:
对于集合中的每个元素:
查找表中的出现次数,将其添加到表的总计中。如果得到奇怪的结果,则拒绝该集
需要时间O(n * N)+ O(n ^ N)+ O(n ^ N * T * N),其为(对于T = N / 2):O(N ^ 3 * n ^ N如果N与n相比被认为是常数,则为O(n ^ N)。
也许有一个完全不同的智能算法不能生成具有N个元素的所有集合,但无论如何可能会发生你的问题有O(n ^ N)个答案,所以你不能这样做在最坏的情况下,这要好得多。 (如果N与n相比被认为是常数)。
答案 1 :(得分:0)
如果你没有太多的桌子,这个很好用。如果你有超过31个,你必须将位向量的格式从int更改为更复杂的东西。
评论解释了它是如何运作的
N=4
TABLES = [
[0,1,9,2,8,5],
[5,3,2,7,6,0],
[7,6,4,3,9,0],
[4,1,0,7,5,8],
[9,7,11,10,2,12]
]
#Make a bit mask for each item, with a bit for each table
#The table's bit is 1 if the number occurs an even number
#of times in the table
#A set of N items is then valid iff the masks for those items
#XOR to 0
MASKS={}
bit=1
for table in TABLES:
for val in table:
MASKS[val] = MASKS.get(val,0) ^ bit
bit*=2
ITEMS=sorted(MASKS.keys())
#Make REACHABLE[n][val] = the highest position pos such that
#you can make XOR value val using n elements at positions >= pos
REACHABLE=[]
for n in range(0,N):
REACHABLE.append({})
REACHABLE[0][0]=len(ITEMS)
for pos in range(len(ITEMS)-1,-1,-1):
itemval=MASKS[ITEMS[pos]]
for n in range(N-1,1,-1):
for testkey in REACHABLE[n-1].keys():
newval=itemval^testkey
REACHABLE[n][newval]=REACHABLE[n].get(newval,pos)
REACHABLE[1][itemval]=REACHABLE[1].get(itemval,pos)
#now print all the solutions using the REACHABLE array to ensure that we
#don't go down any non-viable paths
def printSolutions(prefix, needval, startpos, count):
if count<1:
if needval==0:
print(prefix)
return
for pos in range(startpos,len(ITEMS)):
testval=needval^MASKS[ITEMS[pos]]
if REACHABLE[count-1].get(testval,-1) > pos:
prefix.append(ITEMS[pos])
printSolutions(prefix,testval,pos+1,count-1)
prefix.pop()
printSolutions([],0,0,N)
使REACHABLE
数组取O(N * n * 2 ^(num_tables))并产生输出需要O(n * number_of_solutions)。空间复杂度为O(N * 2 ^(num_tables))。
显然,如果表的数量很大,这种算法可能效率低下。如果你必须支持大量的表,那么你可以在REACHABLE
中使用类似Bloom过滤器(但使用XOR)而不是原始位向量。它在加速输出传递方面不会那么好,但是REACHABLE
将会更小更快生成。
以下是上述程序的输出:
[0, 1, 2, 9]
[0, 2, 4, 10]
[0, 2, 4, 11]
[0, 2, 4, 12]
[0, 2, 8, 9]
[1, 3, 6, 8]
[1, 4, 9, 10]
[1, 4, 9, 11]
[1, 4, 9, 12]
[1, 8, 10, 11]
[1, 8, 10, 12]
[1, 8, 11, 12]
[2, 3, 5, 7]
[2, 5, 6, 7]
[3, 6, 10, 11]
[3, 6, 10, 12]
[3, 6, 11, 12]
[4, 8, 9, 10]
[4, 8, 9, 11]
[4, 8, 9, 12]