Performance 找出两个列表之间的相似之处
我有两个数字列表(L1和L2)。我必须找出L1的任何组合是否在L2数字的任何组合中 我尝试了通过powerset()函数的双循环。然而,它是缓慢的 powerset()生成器:technomancy.org/python/powerset-generator-python 我不发布代码,因为我需要的是一些想法、方法或任何可以启发我的东西Performance 找出两个列表之间的相似之处,performance,Performance,我有两个数字列表(L1和L2)。我必须找出L1的任何组合是否在L2数字的任何组合中 我尝试了通过powerset()函数的双循环。然而,它是缓慢的 powerset()生成器:technomancy.org/python/powerset-generator-python 我不发布代码,因为我需要的是一些想法、方法或任何可以启发我的东西 额外的问题:从长度和数字范围来看,ListA可能是一个巨大的列表如果您仍然处于可以生成完整功率集的区域(我们不必尝试解决这个问题),那么您可以简单地对功率集进行
额外的问题:从长度和数字范围来看,ListA可能是一个巨大的列表如果您仍然处于可以生成完整功率集的区域(我们不必尝试解决这个问题),那么您可以简单地对功率集进行排序(根据其总和的值)并按顺序进行比较,与合并排序的方式相同。这会将运行时间从
O(2^N*2*M)
减少到O(2^N+2^M)
,仍然不太好,但它确实会将有效问题大小从O(N+M)
减少到O(最大(N,M)
这里是动态规划方法。如果你有整数,它会很好地工作。这里的好处是你只跟踪一种方法来获得任何特定的和,这意味着你的性能受和的数量限制
def all_sums (numbers):
answer = {0: None}
for n in numbers:
next_answer = {}
for s, path in answer.iteritems():
next_answer[s] = path
next_answer[round(s + n, 8)] = [n, path]
answer = next_answer
if answer[0] is None:
answer.pop(0)
return answer
def find_matching_sum (numbers1, numbers2):
sums1 = all_sums(numbers1)
sums2 = all_sums(numbers2)
for s1, path1 in sums1.iteritems():
if s1 in sums2:
return [s1, path1, sums2[s1]]
return None
listA = [455, 698, 756, 3.56, -9]
listB = [526,55,943,156,531,304,618,911,598,498,268,926,899,898,131,966,303,936,509,67,976,639,74,935,23,226,422,280,64,975,583,596,583]
print(find_matching_sum(listA, listB))
对于浮点数,我建议尝试乘以一个公分母得到整数。这是为了解决
0.1+0.2!=0.3
问题。还要注意的是,使用浮点数很容易得到非常、非常多的可能和,因此动态规划方法不再是一个胜利。对于极端的充分考虑<代码> [,8, 4, 2,1,0.5,0.25,0.125,…]现在整个powerset都出来玩了…不确定您是否还在寻找答案,但您实际上可以扩展您在OP中提到的子类2和子类3的硬币兑换方法。这里的想法是利用您在动态编程方法中创建的记忆表。请注意,您需要d在两个数组中都有正数(可以是浮点数),以获得最佳可能的解决方案
考虑两个阵列:
[4,3,5,1]
和[2,6,4,3]
让我们使用硬币兑换方法为第一个数组创建记忆表,其中所需的最大总和是数组中所有元素的总和,在本例中为13。记忆表如下所示:
0 1 2 3 4 5 6 7 8 9 10 11 12 13
4 T F F F T F F F F F F F F F
3 T F F T T F F T F F F F F F
5 T F F T T T F T T T F F T F
1 T T F T T T T T T T T F T T
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
2 T F T F F F F F F F F F F F F F
6 T F T F F F T F T F F F F F F F
4 T F T F T F T F T F T F T F F F
3 T F T T T T T T T T T T T T F T
对于第二个数组,总和为15,该表如下所示:
0 1 2 3 4 5 6 7 8 9 10 11 12 13
4 T F F F T F F F F F F F F F
3 T F F T T F F T F F F F F F
5 T F F T T T F T T T F F T F
1 T T F T T T T T T T T F T T
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
2 T F T F F F F F F F F F F F F F
6 T F T F F F T F T F F F F F F F
4 T F T F T F T F T F T F T F F F
3 T F T T T T T T T T T T T T F T
如果您看到这两个表的最后一行,您可以很容易地得出结论,无论哪一列的值为T,该特定列号都可以表示为给定数组中某些元素的总和。您如何找到这些元素?您可以在现有的记忆表中简单地回溯所有可能的方法来获得该特定列的总和。St对于单元格值为T
的任何列,从最后一行开始计算art。然后,您可以回溯使用该特定列的所有T值,并相应地调整总和
现在转到主要部分,关于如何知道哪个子序列提供相同的和。OP的案例4。好吧,一旦您使用最后一行为所有可能的和形成了上述子序列,您就可以逐列比较两个记忆表的最后一行,以找出两个数组中实际形成的和,并返回associ根据这些和存储的非对称子序列。例如,在给定两个数组的情况下,上述两个数组元素形成的公共和将是[3,4,5,6,7,8,9,10,12,13]
,使用上面讨论的方法,您可以将这些和映射到给出这些和的数组列表,从而返回这些数组作为结果
这种情况下的时间复杂度为O(n1*s1+n2*s2)
其中,ni
和si
是数组ai
中元素的数量和总和,我认为您也可以将此方法扩展到k
给定数组
如果有人在这里发现任何缺陷,请告诉我。这是一种比我之前的答案(我已删除)好得多的方法。此解决方案使用子集和函数(iSubsuminIndex)这将返回索引而不是值。公共和搜索的工作原理是,在反转其中一个列表中的元素后合并两个列表。然后,在组合列表中查找零的子集和,将从两个列表中生成一个组合的元素集,形成公共和。构成零和的元素可以在两个集合中分离d在他们的名单或原产地上 子集和函数(iSubsuminIndex)使用了一种比我以前的答案更好的方法。这种新算法不太容易出现“最坏情况”模式。它与旧算法(即100个项目列表的亚秒响应)一样快,甚至更快: 该函数返回产生公共和的所有可能的索引组合。这包括一个列表中的元素组合,这些元素的总数为零,因此与另一个列表中的空子集相匹配 如果只需要以下内容,则可以过滤输出:
- 唯一值组合
- 不同的左/右模式
- 非空子集
listA = [455, 698, 756, 3,56, -9]
listB = [526,55,943,156,531,304,618,911,598,498,268,926,899,898,131,966,303,936,509,67,976,639,74,935,23,226,422,280,64,975,583,596,583]
for iA,iB in iCommonSumIndexes(listA,listB):
sA = [listA[i] for i in iA]
sB = [listB[i] for i in iB]
print(sum(sA),sA,sB)
1454 [698, 756] [526, 226, 422, 280]
1454 [698, 756] [156, 304, 498, 74, 422]
1510 [698, 756, 56] [526, 156, 268, 74, 422, 64]
1510 [698, 756, 56] [526, 498, 422, 64]
1454 [698, 756] [156, 422, 280, 596]
754 [698, 56] [268, 422, 64]
1510 [698, 756, 56] [598, 268, 74, 226, 280, 64]
1510 [698, 756, 56] [156, 618, 598, 74, 64]
756 [756] [618, 74, 64]
...