Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将列表拆分为两部分,尽可能等于总和_Python_Algorithm_Split - Fatal编程技术网

Python 将列表拆分为两部分,尽可能等于总和

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

我想把这整件事弄得头昏眼花,但我似乎不明白。基本上,我有一个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 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),请用
替换最后一个循环:
。否则会发生堆栈溢出,这不是问题所在(当差异不为零时,函数不应进入该循环)。现在修好了。