【问题标题】:Find subarray that sums to given value in Python在Python中查找总和为给定值的子数组
【发布时间】:2017-02-20 15:11:13
【问题描述】:

如果给我一个子数组 [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

【问题讨论】:

  • 与您的问题无关:使用值 TrueFalse(布尔值)而不是字符串 'True''False'
  • 也没有直接关系:您总是使用 a[0] 作为解决方案的一部分。如果解决方案不包含它怎么办?
  • 你是对的!当我第一次调用它时,我应该将它添加到我的函数中。
  • 除了你哪里出错之外的一些批评。您正在为函数提供许多参数,最好使用带有类或实例变量的类,这样您就没有那么多参数。如果您将变量命名为有意义的东西,您的代码会更清晰,例如调用“w”权重而不是在其旁边添加注释;对于 checkForWeight 的第一个局部变量尤其如此。最好避免使用小写“l”和大写“o”,因为它们很容易与 1 和 0 混淆。
  • 还将可变类型(如列表)传递给函数然后更改它们在这里真的很混乱,并且在您的实现中不需要

标签: python recursion sub-array


【解决方案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 建议的那样)

【讨论】:

    【解决方案2】:

    直接的问题是您将 a[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
    

    我确实建议您遵循 cmets 中的建议:与其传递太多东西,不如专注于局部解决方案的本地控制。

    尝试两种解决方案:使用和不使用当前元素。您的递归调用将如下所示:

    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]**.
    

    这会让你动起来吗?

    【讨论】:

      【解决方案3】:

      您是否需要 任何 子数组来匹配您的总和?还是所有子数组? (或者最短的,还是最长的?)正确的答案将高度依赖于此。

      顺便说一句,这是背包问题的一个变种: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(n choose n/2) 主导。)很少有面试候选人会这样回答:

      这并没有尽可能快,但它与最快的速度相差无几,并且可能是开发人员工作时间的最佳投资回报率,无论是在实施和维护方面。当然,除非我们解析的数据集很大,在这种情况下,我建议放宽要求,返回一些可以用 O(n^2) 动态规划解决方案计算的解决方案的启发式算法。”

      你可以利用它来脱颖而出。

      【讨论】:

      • 这确实类似于背包问题。我需要找到所有可能的子数组。我相信递归将是最简单的方法。我想找到答案,然后实施更好的方法。
      猜你喜欢
      • 1970-01-01
      • 2017-01-12
      • 1970-01-01
      • 2020-04-06
      • 2020-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多