Python子集求和

bfnvny8b  于 2023-02-11  发布在  Python
关注(0)|答案(7)|浏览(151)

我正在尝试编写一个函数,它不仅可以确定集合的子集之和是否等于所需的目标数,而且还可以打印出作为解的子集。
下面是查找子集是否存在的代码:

def subsetsum(array,num):

    if num == 0 or num < 1:
        return False
    elif len(array) == 0:
        return False
    else:
        if array[0] == num:
            return True
        else:
            return subsetsum(array[1:],(num - array[0])) or subsetsum(array[1:],num)

我如何修改这个来记录子集本身,以便我可以打印它?提前感谢!

ycl3bljg

ycl3bljg1#

基于您的解决方案:

def subsetsum(array,num):

    if num == 0 or num < 1:
        return None
    elif len(array) == 0:
        return None
    else:
        if array[0] == num:
            return [array[0]]
        else:
            with_v = subsetsum(array[1:],(num - array[0])) 
            if with_v:
                return [array[0]] + with_v
            else:
                return subsetsum(array[1:],num)
nfzehxib

nfzehxib2#

进行修改,以便在匹配发生时检测重复项和进一步的解决方案

def subset(array, num):
    result = []
    def find(arr, num, path=()):
        if not arr:
            return
        if arr[0] == num:
            result.append(path + (arr[0],))
        else:
            find(arr[1:], num - arr[0], path + (arr[0],))
        find(arr[1:], num, path)
    find(array, num)
    return result
a0x5cqrl

a0x5cqrl3#

你可以改变你的方法来更容易地做到这一点,比如:

def subsetsum(array, num):
    if sum(array) == num:
        return array
    if len(array) > 1:
        for subset in (array[:-1], array[1:]):
            result = subsetsum(subset, num)
            if result is not None:
                return result

这将返回有效子集或None

flmtquvp

flmtquvp4#

我想我会再找个解决办法。
我们可以将列表子集的每个选择Map到一个(填充0的)二进制数,其中0表示不取列表中对应位置的成员,1表示取。
因此,使用0101屏蔽[1, 2, 3, 4]将创建子列表[2, 4]
因此,通过生成0到2^LENGTH_OF_LIST范围内的所有0填充二进制数,我们可以迭代所有选择。如果我们使用这些子列表选择作为掩码,并对选择求和,我们就可以知道答案。
这是怎么做到的:

#!/usr/bin/env python

# use a binary number (represented as string) as a mask
def mask(lst, m):
    # pad number to create a valid selection mask 
    # according to definition in the solution laid out 
    m = m.zfill(len(lst))
    return map(lambda x: x[0], filter(lambda x: x[1] != '0', zip(lst, m)))

def subset_sum(lst, target):
    # there are 2^n binary numbers with length of the original list
    for i in xrange(2**len(lst)):
        # create the pick corresponsing to current number
        pick = mask(lst, bin(i)[2:])
        if sum(pick) == target:
            return pick
    return False

print subset_sum([1,2,3,4,5], 7)

输出:

[3, 4]

为了返回所有可能性,我们可以使用生成器(唯一的变化是在subset_sum中,使用yield代替return,并删除return False保护):

#!/usr/bin/env python

# use a binary number (represented as string) as a mask
def mask(lst, m):
    # pad number to create a valid selection mask 
    # according to definition in the solution laid out 
    m = m.zfill(len(lst))
    return map(lambda x: x[0], filter(lambda x: x[1] != '0', zip(lst, m)))

def subset_sum(lst, target):
    # there are 2^n binary numbers with length of the original list
    for i in xrange(2**len(lst)):
        # create the pick corresponsing to current number
        pick = mask(lst, bin(i)[2:])
        if sum(pick) == target:
            yield pick

# use 'list' to unpack the generator
print list(subset_sum([1,2,3,4,5], 7))

输出:

[[3, 4], [2, 5], [1, 2, 4]]
    • 注意:**虽然不使用零填充掩码也可以,因为它只会以相反的顺序选择原始列表中的成员-我没有选中它,也没有使用它。

我没有使用它,因为它不太明显(对我来说)是怎么回事,这样的trenary类面具(1,0或无),我宁愿有一切很好地定义。

3pvhb19x

3pvhb19x5#

通过Recursion打印所有子集的方法稍有不同。

def subsetSumToK(arr,k):
    if len(arr)==0:
        if k == 0:
            return [[]]
        else:
            return []
    
    output=[]
    if arr[0]<=k: 
        temp2=subsetSumToK(arr[1:],k-arr[0])  #Including the current element 
        if len(temp2)>0:
            for i in range(len(temp2)):
                temp2[i].insert(0,arr[0])
                output.append(temp2[i])
    
    temp1=subsetSumToK(arr[1:],k)            #Excluding the current element
    if len(temp1)>0:
        for i in range(len(temp1)):
            output.append(temp1[i])
    return output

arr=[int(i) for i in input().split()]
k=int(input())
sub=subsetSumToK(arr,k)
for i in sub:
    for j in range(len(i)):
        if j==len(i)-1:
            print(i[j])
        else:
            print(i[j],end=" ")
bjg7j2ky

bjg7j2ky6#

您可以使用迭代方法,而不是使用递归。

def desiredSum(array, sum):

  numberOfItems = len(array)
  storage = [[0 for x in range(sum + 1)] for x in range(numberOfItems + 1)]

  for i in range(numberOfItems + 1):
    for j in range(sum + 1):

        value = array[i - 1]

        if i is 0: storage[i][j] = 0
        if j is 0: storage[i][j] = 1

        if value <= j:

            noTake = storage[i - 1][j]
            take = storage[i - 1][j - value]
            storage[i][j] = noTake + take

  return storage[numberOfItems][sum]
7xllpg7q

7xllpg7q7#

稍微更新了下面的代码,以返回此问题的所有可能组合。当输入作为子集([4,3,1],4)给定时,上面线程中的代码段不会打印所有可能组合

def subset(array, num):
    result = []
    def find(arr, num, path=()):
        if not arr:
            return
        if arr[0] == num:
            result.append(path + (arr[0],))
        else:
            find(arr[1:], num - arr[0], path + (arr[0],))
        find(arr[1:], num, path)
    find(array, num)
    return result

相关问题