简体   繁体   English

使用集合的子集求和(Python)

[英]Subset Sum using Sets (Python)

I'm trying to solve the Subset Sum problem using Set and recursion in python.我正在尝试使用 python 中的 Set 和递归来解决子集和问题。 I've found a lot of solutions with an array, but none with a set.我找到了很多带有数组的解决方案,但没有找到带有集合的解决方案。

Here is my code:这是我的代码:

def checkForSubSet(set, sum):

  if len(set) == 0 or sum < 0:
      return False

  e = set.pop() 

  if sum == e:
     return True

  return checkForSubSet(set, sum - e) or checkForSubSet(set, sum)

if __name__ == '__main__':  

  set = {3, 34, 4, 12, 5, 2}
  sum = 17
  if (checkForSubSet(set, sum) == True) :
      print("Found a subset with given sum")
  else :
      print("No subset with given sum")

sometimes its works and sometimes not... any idea?有时它的作品,有时不是......任何想法? ty for any help!求任何帮助!

Your basic error is that you pop() a value from the input set.您的基本错误是您从输入集中pop()一个值。 This means that in all subsequent calls you will not have that value available.这意味着在所有后续调用中,您将无法获得该值。 This is easily seen with a print statement, where I've replaced sum and set with names that don't clash with builtins:使用 print 语句很容易看出这一点,其中我用不与内置函数冲突的名称替换了sumset

def checkForSubSet(components, target):
  print(f"{components=} {target=}")
  if len(components) == 0 or target< 0:
      return False
  e = components.pop() 
  if target == e:
     return True
  return checkForSubSet(components, target - e) or checkForSubSet(components, target)

>>> checkForSubSet({3,2,1}, 4)
components={1, 2, 3} target=4
components={2, 3} target=3
components={3} target=1
components=set() target=-2
components=set() target=1
components=set() target=3
components=set() target=4
False

We see that the set gets ordered.我们看到集合是有序的。 1 is tested first, and then popped off. 1先测试,然后弹出。 And so on until 3 is popped off and then, hitting the base case, the function returns False .依此类推,直到弹出 3 ,然后在基本情况下, function 返回False It tries the alternative cases - but the set (which persists throughout) no longer has items in it.它会尝试其他情况 - 但集合(始终存在)中不再包含项目。 Thus, as it goes back up the tree it is testing against an empty set.因此,当它返回树时,它正在针对空集进行测试。

Recursion is always about a base case and an iterative case:递归总是关于基本情况和迭代情况:

def has_subset(components: Set[int], target: int) -> bool:
    print(f"{components=} {target=}")
    # Base Case: check for truth once the set is empty
    if 0 == target:
        return True
    # Iterative Case: iterate through each option you have for reducing the size of the set by one
    else:
        return any(has_subset(components - {item}, target - item) for item in components)

Here, we check the base case of an empty set.在这里,我们检查空集的基本情况。 If we have an empty set and the target is 0, we return true.如果我们有一个空集并且目标是 0,我们返回 true。 Otherwise, we return false.否则,我们返回 false。

The iterative case is (almost always) more interesting.迭代案例(几乎总是)更有趣。 Here, we simply iterate through all elements of the set, and check what has_subset() returns if we remove one item and reduce our target by that item.在这里,我们简单地遍历集合的所有元素,并检查如果我们删除一个项目并通过该项目减少我们的目标, has_subset()返回什么。 any() lets us return the first result we get that is True , or False if we exhaust all options. any()让我们返回我们得到的第一个结果True ,如果我们用尽所有选项,则返回False Note, however, that we are using the construct components - {item} which takes your initial set and returns a new set that includes all the elements except those in the set {item} .但是请注意,我们使用的是构造components - {item} ,它接受您的初始集合并返回一个新集合,其中包括除了集合{item}中的元素之外的所有元素。 Since this is a new set, it does not fall prey to the previous problem when we recurse with it.由于这是一个新集合,因此当我们对其进行递归时,它不会成为前一个问题的牺牲品。

There are optimizations that can happen (what happens if your choice makes target a negative number?), but this should still work.可能会发生一些优化(如果您的选择使target为负数会发生什么?),但这应该仍然有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM