【问题标题】:Python Subset SumPython 子集总和
【发布时间】:2014-04-15 15:13:09
【问题描述】:

我正在尝试编写一个函数,该函数不仅可以确定集合的子集的总和是否添加到所需的目标数,还可以打印作为解决方案的子集。

这是我查找子集是否存在的代码:

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)

如何修改它以记录子集本身以便我可以打印它?提前致谢!

【问题讨论】:

  • 返回子集的元组以及总和是否增加到您想要的目标数。喜欢return subset, True
  • 不知道该怎么做。我如何获得元组?
  • 您是否尝试在网上搜索如何做到这一点? Here's one of the top results on google.
  • 对不起,我知道如何返回多个值。那不是问题。我想知道如何将加起来达到所需数字的值添加到列表或元组中。现在该函数仅确定 True 或 False。我需要用值填充元组。
  • 你需要先自己做一些小的努力。 Take a look at the append() method of lists.

标签: python subset-sum


【解决方案1】:

根据您的解决方案:

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)

【讨论】:

  • num == 0 or num &lt; 1 收到来自冗余部门的警告!
  • 这不适用于 [1,3,4,5,6] 和目标 9。它只返回 [1,3,5]
【解决方案2】:

Samy 答案的略微修改版本以打印所有可能的组合。

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

【讨论】:

    【解决方案3】:

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

    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

    【讨论】:

    • @user2872761 哎呀,错字;固定
    • 这很完美。但是,我无法绕过 for 循环。或多或少对该特定python语法的解释是什么?在特定的迭代中,它的值是什么(子集和两个切片)?它是否在每次迭代时遍历每个子集值和两个数组(切片)?我问是因为我正在尝试将解决方案转换为 PHP。
    • 您为什么不输入一些prints 并找出答案?
    • @ArnabDatta 此代码仅处理连续子集,您必须稍微修改它以处理非连续子集。
    • 我试过你的代码,它不能很好地处理像子集([2,5,3,4,6], 7)这样的数组,它返回 [5,2],但它应该也返回[3,4]。
    【解决方案4】:

    我想我会再加入另一个解决方案。

    我们可以将列表子集的每个选择映射到一个(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]]
    

    注意:虽然不用零填充掩码也可以,因为它只会以相反的顺序选择原始列表的成员 - 我没有检查它,也没有使用它。

    我没有使用它,因为(对我而言)这种类似三元组的面具(1、0 或什么都没有)发生了什么不太明显,我宁愿把所有东西都定义好。

    【讨论】:

      【解决方案5】:

      通过递归打印所有子集的有点不同的方法。

      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=" ")
      

      【讨论】:

        【解决方案6】:

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

        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]
        

        【讨论】:

          猜你喜欢
          • 2012-02-19
          • 2020-01-26
          • 2021-11-14
          • 2015-06-18
          • 2020-03-24
          • 1970-01-01
          • 2011-09-02
          • 2013-10-30
          • 1970-01-01
          相关资源
          最近更新 更多