在Python中查找总和为给定值的子数组

时间:2016-10-11 22:59:44

标签: python recursion sub-array

如果给出一个子阵列[1,2,3,4]和值8.我想返回子阵列[1,3,4]。我的代码中有一个错误,我不确定如何修复它,因为我是新手递归。我的Python代码如下。我正在回复打印的值[3,4],这显然不是正确的答案。如何获得数组中的第一个元素?

def main():
    s = 0
    a = [1,2,3,4] # given array
    sa = [] # sub-array
    w = 8 # given weight
    d = False
    d, sa = checkForWeight(a,w,s,d,sa)
    print sa

def checkForWeight(a,w,s,d,sa):
    l = len(a)
    s += a[0]
    sa.append(a[0])
    if s == w:
        d = True
        return d, sa
    else:
        try:
            d, sa = checkForWeight(a[1:],w,s,d,sa)
            if d != True:
                d, sa = checkForWeight(a[2:],w,s,d,sa)
            else:
                return d, sa
        except:
            sa = [] # i put this here because I want to erase the incorrect array
    return d, sa

3 个答案:

答案 0 :(得分:1)

您需要任何子阵列与您的总和相匹配吗?还是所有子阵列? (或者是最短的还是最长的?)正确的答案将高度依赖于此。

顺便说一句,这是背包问题的一个变种:https://en.wikipedia.org/wiki/Knapsack_problem

此外,您的递归策略似乎是复杂的因素。 (如果是代码测试,单凭这可能会使申请人失败。)我强烈建议采用动态编程方法。

修改

如果您需要所有可能的,那么您正在查看NP问题。我建议专注于易于实施/维护,而不是绝对的表现来炫耀你的技能。例如:

import itertools

def find_all_subsets_that_sum(elements, total):
  for i in range(len(elements)):
    for possible in itertools.combinations(elements, i+1):
      if sum(possible)==total:
        yield possible

print list(find_all_subsets_that_sum([1,2,3,4,5,6,7,8,9,10], 10))

不是绝对最快的(你可以在自动递归解决方案中做很多修剪),但它与你提出的任何更复杂的解决方案都是相同的大O. (所有解决方案都将由O(n选择n / 2)主导。)很少有面试候选人会回答:

  

这并不像它可能的那么快,但它在最快的吐痰距离内,并且可能是开发时间内实施和维护的最佳投资回报率。当然,除非我们正在解析的数据集很大,在这种情况下,我建议放宽要求,以返回可以使用O(n ^ 2)动态编程解决方案计算的一些解决方案的启发式。“

你可以用它来脱颖而出。

答案 1 :(得分:1)

当前的问题是你在函数的顶部附加一个[0]到sa,但是后来用子调用的返回值来破坏它。要修补此问题,请在返回最终结果之前添加一个子句:

    except:
        sa = [] # i put this here because I want to erase the incorrect array
if d:
    sa = [a[0]] + sa
print "Leave: drop", d,sa
return d, sa

我建议您遵循评论中的建议:不要传递太多东西,而是集中精力控制局部解决方案。

尝试两种方式的解决方案:使用和不使用当前元素。你的递归调用看起来像这样:

sa = checkForWeight(a[1:], w)         # Solutions without first element
    -- and --
sa = checkForWeight(a[1:], w-a[0])    # Solutions using first element

You don't have to return a success flag; if **sa** is None or empty, the call failed to find a solution.  If it succeeded, in the **w-a[0]** call, then you also need to prepend each solution in **sa** with **a[0]**.

这会让你感动吗?

答案 2 :(得分:1)

我做了一个有效的递归解决方案,希望它有所帮助:

def main():
    success, solution = WeightChecker((1,2,3,4)).check(8)
    print solution

class WeightChecker(object):
    def __init__(self, to_check):
        self._to_check = to_check
    def check(self, weight):
        return self._check((), 0, weight)
    def _check(self, current_solution, index_to_check, remaining_weight):
        if remaining_weight == 0:
            return True, current_solution
        if index_to_check == len(self._to_check):
            return False, ()
        current_check = self._to_check[index_to_check]
        success, solution = self._check(current_solution + (current_check, ), index_to_check + 1, remaining_weight - current_check)
        if not success:
            success, solution = self._check(current_solution, index_to_check + 1, remaining_weight)
        return success, solution

(动态编程方法比keredson建议的更好)