Python 将列表拆分为两部分,尽可能等于总和
我想把这整件事弄得头昏眼花,但我似乎不明白。基本上,我有一个int列表。将这些int值相加等于15。我想把一个列表分成两部分,但同时,使每个列表在总数上尽可能接近彼此。对不起,我没有解释清楚 例如:Python 将列表拆分为两部分,尽可能等于总和,python,algorithm,split,Python,Algorithm,Split,我想把这整件事弄得头昏眼花,但我似乎不明白。基本上,我有一个int列表。将这些int值相加等于15。我想把一个列表分成两部分,但同时,使每个列表在总数上尽可能接近彼此。对不起,我没有解释清楚 例如: list = [4,1,8,6] 我想实现这样的目标: list = [[8, 1][6,4]] 第一个列表加起来等于9,另一个等于10。这正是我想要的,因为它们尽可能靠近 我现在所拥有的: my_list = [4,1,8,6] total_list_sum = 15 def divi
list = [4,1,8,6]
我想实现这样的目标:
list = [[8, 1][6,4]]
第一个列表加起来等于9,另一个等于10。这正是我想要的,因为它们尽可能靠近
我现在所拥有的:
my_list = [4,1,8,6]
total_list_sum = 15
def divide_chunks(l, n):
# looping till length l
for i in range(0, len(l), n):
yield l[i:i + n]
n = 2
x = list(divide_chunks(my_list, n))
print (x)
但是,这只是把它分成两部分
任何帮助都将不胜感激 我想你要找的是爬山算法。我不确定这将涵盖所有情况,但至少对您的示例有效。如果我想到一个反例或什么的话,我会更新这个 让我们调用您的号码列表
vals
vals.sort(reverse=true)
a,b=[],[]
for v in vals:
if sum(a)<sum(b):
a.append(v)
else:
b.append(v)
vals.sort(反向=真)
a、 b=[],[]
对于VAL中的v:
如果总和(a)使用itertools.组合
(详细信息)。首先,让我们定义一些函数:
def difference(sublist1, sublist2):
return abs(sum(sublist1) - sum(sublist2))
def complement(sublist, my_list):
complement = my_list[:]
for x in sublist:
complement.remove(x)
return complement
函数difference
计算列表之间的“距离”,即两个列表之和的相似程度<代码>补码
返回我的列表
中不在子列表
中的元素
最后,您要寻找的是:
def divide(my_list):
lower_difference = sum(my_list) + 1
for i in range(1, int(len(my_list)/2)+1):
for partition in combinations(my_list, i):
partition = list(partition)
remainder = complement(partition, my_list)
diff = difference(partition, remainder)
if diff < lower_difference:
lower_difference = diff
solution = [partition, remainder]
return solution
test1 = [4,1,8,6]
print(divide(test1)) #[[4, 6], [1, 8]]
test2 = [5,3,2,2,2,1]
print(divide(test2)) #[[5, 3], [2, 2, 2, 1]]
def divide(我的列表):
下_差=和(我的_列表)+1
对于范围(1,int(len(my_list)/2)+1内的i:
对于组合分区(我的_列表,i):
分区=列表(分区)
余数=补码(分区,我的列表)
差异=差异(分区,余数)
如果差值<下限差值:
下_差=diff
解决方案=[分区,余数]
返回溶液
test1=[4,1,8,6]
打印(除法(测试1))#[4,6],[1,8]]
test2=[5,3,2,2,2,1]
打印(除法(测试2))35;[[5,3],[2,2,2,1]]
基本上,它尝试子列表的每一个可能的划分,并返回具有最小“距离”的一个
如果您想让它快一点,您可以返回差异为0的第一个组合。您可以使用递归算法和列表的“暴力”分区。从目标差异为零开始,逐步增加对两个列表之间差异的容忍度:
def sumSplit(left,right=[],difference=0):
sumLeft,sumRight = sum(left),sum(right)
# stop recursion if left is smaller than right
if sumLeft<sumRight or len(left)<len(right): return
# return a solution if sums match the tolerance target
if sumLeft-sumRight == difference:
return left, right, difference
# recurse, brutally attempting to move each item to the right
for i,value in enumerate(left):
solution = sumSplit(left[:i]+left[i+1:],right+[value], difference)
if solution: return solution
if right or difference > 0: return
# allow for imperfect split (i.e. larger difference) ...
for targetDiff in range(1, sumLeft-min(left)+1):
solution = sumSplit(left, right, targetDiff)
if solution: return solution
# sumSplit returns the two lists and the difference between their sums
print(sumSplit([4,1,8,6])) # ([1, 8], [4, 6], 1)
print(sumSplit([5,3,2,2,2,1])) # ([2, 2, 2, 1], [5, 3], 1)
print(sumSplit([1,2,3,4,6])) # ([1, 3, 4], [2, 6], 0)
def sumSplit(左、右=[],差=0):
sumLeft,sumRight=和(左),和(右)
#如果left小于right,则停止递归
如果结果列表的长度应该相同吗?对不起,不确定您的意思这是否回答了您的问题@Jonathon如果您的输入是[1,1,1,3]
,则[[1,1,1],[3]]
是有效的输出吗?技术上是,但需要将其分为两个列表。即使每个列表的总和稍有不同,它也不会将列表[10,11,14,16,19]按总和分成两等分,而是返回[16,14],[19,11,10],而不是该组合的正确答案是什么?我想这可能是DP的问题,应该是[10,11,14],[16,19]。这种安排似乎是该解决方案的最坏情况。一个更简单的例子是[2,2,2,3,3],这与此类似。在最后的迭代中,和(a)=和(b),它的最小元素是2,然后将其添加到其中一个数组中,使它们不平衡。该解决方案的一个有趣特性是,各部分之和的差值不能超过最小元素。这个问题可以用动态规划来解决,但只有当元素的大小受到约束时,否则时间复杂度会呈指数级增长。我不是在关注元素的大小。输入的大小不会影响复杂性。实际运行时,当然。如果所有元素都是小于常数C的正整数,并且列表大小为n,则存在复杂度为O(C*n)的DP解决方案。但若元素是无约束的,那个么它就是划分问题,它是NP难的,不能在多项式时间内求解。它有时被称为伪多项式时间动态编程。它几乎可以工作,但无法返回大小列表的解决方案2@user13044086它在我的机器里工作。可能是“版本”问题(?)我注意到,如果列表解决方案中没有为列表[0,2]分配零,就会发生这种情况。您可以用diff@user13044086替换比较来修复它,谢谢!问题来自较低的\u差值的初始值
可能存在一个“最智能”的初始值。对于范围内的targetDiff(差值+1,sumlefit min(left)+1),请用替换最后一个循环:
。否则会发生堆栈溢出,这不是问题所在(当差异不为零时,函数不应进入该循环)。现在修好了。