【问题标题】:Display subset in recursive algorithm for subset sum在递归算法中显示子集和的子集
【发布时间】:2016-02-01 03:58:26
【问题描述】:

我有以下递归解决子集和问题的算法:

def findSubset(alist, targ, i, sumsofar):
    if sumsofar == targ:
        return True
    if i == len(alist):
        return False
    inc = findSubset(alist, targ, i+1, sumsofar+alist[i])
    noninc = findSubset(alist, targ, i+1, sumsofar)
    return inc or noninc

该算法运行良好,但它只给出一个布尔值的答案。所以如果我这样称呼它:

alist = [4, 6, 21, 29, 37, 50]
findSubset(alist, 76, 0, 0)
>>> True

但我希望它返回[4, 6, 29, 37]

这是我改变算法的尝试:

def findSubset(alist, targ, i, sumsofar, new):
    if sumsofar == targ:
        return new
    if i == len(alist):
        return []
    inc = findSubset(alist, targ, i+1, sumsofar+alist[i], new.append(alist[i]))
    noninc = findSubset(alist, targ, i+1, sumsofar, new)
    return inc or noninc

在哪里使用它:

alist = [4, 6, 21, 29, 37, 50]
findSubset(alist, 76, 0, 0, [])
>>>AttributeError: 'NoneType' object has no attribute 'append'

我必须做些什么才能让它工作,甚至可能吗?

【问题讨论】:

  • return inc or nonionic改成return inc if inc else noninc?
  • @vyscond 我仍然遇到同样的错误
  • append() 修改列表并返回None

标签: python recursion subset-sum


【解决方案1】:

我的以下代码有效:

def findSubset(alist, targ, i, sumsofar, listsofar):
    if sumsofar == targ:
        return True, listsofar
    if i == len(alist):
        return False, listsofar
    inc, inclistsofar = findSubset(alist, targ, i+1, sumsofar+alist[i], listsofar + [alist[i]])
    noninc, noninclistsofar = findSubset(alist, targ, i+1, sumsofar, listsofar)

    if inc:
        return inc, inclistsofar
    else:
        return noninc, noninclistsofar

alist = [4, 6, 21, 29, 37, 50]
print findSubset(alist, 76, 0, 0, [])

list.append() 是就地操作。它返回 None 类型,但您需要将列表作为参数传递。

【讨论】:

    【解决方案2】:

    Hengfeng Li 改进的解决方案。使用默认参数可以更好地调用没有零和空列表find_subset(alist, 76)

    def find_subset(alist, targ, i=0, sumsofar=0, listsofar=None):
        if listsofar is None:
            listsofar = []
        if sumsofar == targ:
            return True, listsofar
        if i == len(alist):
            return False, listsofar
        inc, inclistsofar = find_subset(alist, targ, i+1, sumsofar + alist[i], listsofar + [alist[i]])
        noninc, noninclistsofar = find_subset(alist, targ, i+1, sumsofar, listsofar)
    
        if inc:
            return inc, inclistsofar
        else:
            return noninc, noninclistsofar
    
    alist = [4, 6, 21, 29, 37, 50]
    print(find_subset(alist, 76))
    

    更新

    根据 Blckknght 的评论进一步改进:

    def find_subset(alist, targ, i=0, sumsofar=0, listsofar=None):
        if listsofar is None:
            listsofar = []
        if sumsofar == targ:
            return listsofar
        if i == len(alist):
            return None
        inclistsofar = find_subset(alist, targ, i+1, sumsofar + alist[i], 
                                   listsofar + [alist[i]])
        if inclistsofar:
            return inclistsofar
        else:
            noninclistsofar = find_subset(alist, targ, i+1, sumsofar, listsofar)
            return noninclistsofar
    
    alist = [4, 6, 21, 29, 37, 50]
    print(find_subset(alist, 76))
    print(find_subset(alist, 100))
    print(find_subset(alist, 1000))
    print(find_subset(alist, 4))
    print(find_subset(alist, 17))
    

    输出:

    [4, 6, 29, 37]
    [21, 29, 50]
    None
    [4]
    None
    

    【讨论】:

    • 进一步的改进是去掉 incnoninc 布尔值并在没有有效总和时返回 None。如果第一个递归找到结果 (inclistsofar = find_subset(...); if inclistsofar is not None: return inclistsofar),您还可以通过短循环而不进行第二次递归来大大提高性能。
    • @Blckknght 感谢您的提示。现在看起来好多了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-26
    • 2012-02-19
    • 1970-01-01
    • 2014-12-07
    相关资源
    最近更新 更多