【问题标题】:I tried to solve Best Sum problem in Python but I am not able to figure out the issue, please suggest what is wrong我试图在 Python 中解决 Best Sum 问题,但我无法找出问题所在,请提出问题所在
【发布时间】:2021-08-14 20:32:58
【问题描述】:

该函数应返回一个数组,其中包含加起来正好等于目标总和的最短数字组合。如果有两种(或更多)可能性,则返回其中任何一种。

def bestSum(targetSum, numbers, memo = {}):
    if targetSum in memo: return memo[targetSum]
    if targetSum == 0: return []
    if targetSum < 0: return None
    
    shortestCombination = None
    for num in numbers:
        remainder = targetSum - num
        remainderCombination = bestSum(remainder, numbers, memo)
        
        if remainderCombination is not None:
            remainderCombination.append(num) 
            if shortestCombination is None or len(remainderCombination) < len(shortestCombination):                
                shortestCombination = remainderCombination
            
    memo[targetSum] = shortestCombination
    return memo[targetSum]

输入调用:bestSum(4, [2,1])

输出:[2, 2, 1]

预期输出:[2,2]

【问题讨论】:

    标签: python arrays recursion memoization


    【解决方案1】:

    您可以更改此行:

        if targetSum in memo: 
            return memo[targetSum]
    

    进入:

        if targetSum in numbers: 
            return [targetSum]
    

    为什么?因为直到最后一次递归,memo 仍然是空的,所以你永远不会返回带有目标总和的列表。

    这是您的代码,其中进行了一些改进,主要是为了适合 PEP8:

    def best_sum(target_sum, numbers, memo={}):
        if target_sum in numbers:
            return [target_sum]
        if target_sum == 0:
            return []
        if target_sum < 0:
            return None
    
        shortest_combination = None
        for num in numbers:
            remain = target_sum - num
            
            reminder_combination = best_sum(remain, numbers, memo)
    
            if reminder_combination is not None:
                reminder_combination.append(num)
                if shortest_combination is None or len(reminder_combination) < len(shortest_combination):
                    shortest_combination = reminder_combination
    
        memo[target_sum] = shortest_combination
        return shortest_combination
    
    
    if __name__ == '__main__':
        print(best_sum(4, [2, 1]))
        # [2, 2]
    

    【讨论】:

    • 嗨,Dorian,它解决了我提到的问题,但性能下降了。假设如果我们调用 BestSum(300 , [7, 1, 5]) 那么它需要很长时间才能得到结果
    • stackoverflow.com/a/66289797/6251742 我认为这可以解决您的问题。考虑接受它的答案。
    【解决方案2】:

    所以解决方案非常简单,但当时我没有注意到。我们应该使用shortestCombination = remainderCombination.copy(),而不是像shortestCombination = remainderCombination 这样复制列表,这样shortestCombination 和remainderCombination 就不会指向内存中的同一个List。

    这是正确的代码,性能也很好

    def bestSum(targetSum, numbers, memo = {}):
        if targetSum in memo: return memo[targetSum]
        if targetSum == 0: return []
        if targetSum < 0: return None
        
        shortestCombination = None
        for num in numbers:
            remainder = targetSum - num
            remainderCombination = bestSum(remainder, numbers, memo)
            
            if remainderCombination is not None:
                remainderCombination.append(num) 
                if shortestCombination is None or len(remainderCombination) < len(shortestCombination):                
                    shortestCombination = remainderCombination.copy()
                
        memo[targetSum] = shortestCombination
        return shortestCombination
        
    if __name__ == '__main__':
        print(bestSum(4, [2, 1]))    #Output  [2, 2] 
    
        print(bestSum(300, [2, 7]))
        #Output 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 
        #       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7]
    
    

    【讨论】:

      【解决方案3】:

      所以我认为您错过了更多的列表副本,这可能会导致您的备忘录记忆错误。请试试这个,我相信这会给出你的算法遗漏的结果。

      def bestSum(targetSum, numbers, memo={}):
          if targetSum in memo:
              return memo[targetSum]
          if targetSum == 0:
              return []
          if targetSum < 0:
              return None
      
          shortestCombination = None
          for num in numbers:
              remainder = targetSum - num
              remainderCombination = bestSum(remainder, numbers, memo)
      
              if remainderCombination is not None:
                  combination = remainderCombination + [num]
                  if shortestCombination is None or len(combination) < len(shortestCombination):
                      shortestCombination = combination.copy()
      
          print(str(targetSum) + "---------" + str(shortestCombination))
          if shortestCombination:
              memo[targetSum] = shortestCombination.copy()
          else:
              memo[targetSum] = None
          return shortestCombination
      

      【讨论】:

      • 您观察到的变化是通过引用与值传递。稍后可能会更改备忘录。
      • 感谢您的回答
      • @AshishKumar 如果对您有帮助,请检查它是否为正确答案并点赞。
      【解决方案4】:

      我们需要一份备忘录来减少运行时间。 但我们正在处理列表。所以当我们返回一个列表时, 我们应该使用一个 copy(),而不是仅仅返回一个引用。 备忘录化提供了更好的性能。 在返回中间列表的实际副本时,可以确保我们不会处理陈旧的数据。 此外,在 python 中,列表复制可以使用切片来完成。 因此 a = [1,2,3] b = a[:] 等价于 b = a.copy()。 更新我的代码以反映相同的情况。

      对于性能和正确复制来说,这是正确的答案:

      def bestSum(targetSum, numbers, memo):
          if targetSum in memo:
              return memo[targetSum][:]
          if targetSum == 0:
              return []
          if targetSum < 0:
              return None
      
          shortestCombi = None
      
          for num in numbers:
              remainder = targetSum - num
              remainderCombi = bestSum(remainder, numbers, memo)
      
              if remainderCombi is not None:
                  remainderCombi.append(num)
                  if shortestCombi is None or len(remainderCombi) < len(shortestCombi):
                      shortestCombi = remainderCombi[:]
      
          if shortestCombi:
              memo[targetSum] = shortestCombi[:]
          else:
              memo[targetSum] = None
          
          return shortestCombi
      

      【讨论】:

      • 您应该考虑扩展此答案以解释代码及其工作原理。解释为什么这是“正确的[...]性能和正确复制”而其他答案不是。
      • 用一些解释更新了我的帖子
      • 感谢您的回答——
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-26
      • 1970-01-01
      • 2019-03-25
      • 2020-12-13
      • 2023-03-20
      相关资源
      最近更新 更多