微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何通过使用python添加来获取目标 朴素的递归方法DP 算法

如何解决如何通过使用python添加来获取目标 朴素的递归方法DP 算法

我有一个列表和一个目标编号。

l = [1,2,3]

target = 5

方式数如下

  • 1+ 1 + 1 + 1 + 1 = 5
  • 1 + 1 + 1+ 2 =5
  • 1 + 2 + 2 = 5
  • 1 +1 +3 =5
  • 2 + 3 = 5

输出 5 种方式

def countways(l,target ):

    if (target  == 0):
        return 0
    else:
        pass
if __name__ == "__main__":
     l = [1,3],target = 5
     countways(l,target )

我们可以使用原生 python 或 itertools 来实现吗?

解决方法

我假设所有数字都是正数。

您可以使用 itertools 来检查所有 combinations_with_replacement,正如 Ann 所建议的那样,但是对于大量输入,它会变得不必要地缓慢,因为组合数量呈指数级增长。

朴素的递归方法

此版本使用 Nevetha 描述的递归方法,它允许提前返回永远找不到匹配项的分支,但应该进行替换。

与其他结果一样:扩展打印实际被加数相当容易。我们只需添加一个可选的第三个参数,用于给出目前的被加数,并在 target == 0 情况下打印它。

def countWays(elements,target):
    if target < 0:
        return 0

    if target == 0:
        return 1

    total = 0
    for index,element in enumerate(elements):
       total += countWays(elements[index:],target - element)
 
    return total
 
 
if __name__ == '__main__':
    print(countWays([1,2,3],5))
    print(countWays([5,31,32,33,34,35,36,37,38,39,40],30))
    print(countWays([2,3,5,7,11,13,17,19,23,29,37],40))
    print(countWays([1,4,5],200))

DP 算法

如您所见,对于 200 的目标,这已经需要相当长的时间来执行。这是因为在递归结束时,我们总是只向结果添加一个。这可以通过使用动态编程来改进——或者通过简单地添加缓存(示例代码,当然不应在任何实际程序中使用全局变量):

cache = {}
def countWays(elements,target):
    global cache

    if target < 0:
        return 0

    if target == 0:
        return 1

    cache_key = (tuple(elements),target)
    if cache_key in cache:
        return cache[cache_key]

    total = 0
    for index,target - element)

    cache[cache_key] = total
    return total

或者直接构建 dp 数组,如已经讨论过的 here:

def countWays(elements,target):   
    dp = [1] + [0] * target
    for element in elements:
        for i in range(0,target - element + 1):
            dp[i + element] += dp[i]
    return dp[target]
,

您可以使用 itertools.combinations_with_replacement() 方法:

from itertools import combinations_with_replacement as cwr

def countways(l,target):
    return len([1 for i in range(target) for j in cwr(l,i + 1) if sum(j) == target])

print(countways([1,5))

输出:

5

说明

该方法的文档字符串如下:

从输入迭代中返回元素的 r 个长度子序列,允许单个元素重复多次。

所以它就像 itertools.combinations() 方法,期望 itertools.combinations_with_replacement() 方法允许重复元素。

如果您想可视化不同的解决方案:

from itertools import combinations_with_replacement as cwr

def countways(l,target):
    for i in range(target):
        for j in cwr(l,i + 1):
            if sum(j) == target:
                print(j)

countways([1,5)

输出:

(2,3)
(1,1,2)
(1,1)

注意:正如@He3lixxx (+1) 所指出的,这对于大量输入可能会非常慢。您可以通过过滤掉l中大于target的数字,并将target中的range(target)除以max(l)和{{1}来提高效率}},像这样:

min(l)
,

动态规划方法会奏效。此代码输出所有可能的组合。只需打印列表的长度即可获得总数。此外,所有可能的组合都是唯一的,不要重复。

def ways(l,target):
    dp =[ [] for i in range(target+1) ]
    l.sort()
    n=len(l)
    for i in range(n):
        for j in range(l[i],target+1):    
            if j==l[i]:
                dp[j].append([l[i]])
            else:
                if dp[j-l[i]]:   
                    for u in dp[j-l[i]]:       
                        dp[j].append(u+[l[i]])       
    return dp[-1]

if __name__ == "__main__":
     l = [1,3] 
     target = 5
     print(len(ways(l,target)))
     l = [5,40]
     target = 30
     print(len(ways(l,target)))
,

您可以使用 itertools 进行解析,如下例所示:

import itertools 

def countways(l,target): 
    data = []  
    for length in range(1,target+1):  
        data.extend([x for x in itertools.combinations_with_replacement(l,length) if sum(x) == target]) 
    return len(data)

您需要使用 1 和目标之间的所有尺寸创建组合,因此 for 是必要的。在每次迭代中,您保存总和值等于 target 的组合。最后你只需要计算保存的列表。

,

下面的一个作品

从指定列表的元素计算目标的计数方法

def countWays(A,n,target):
 
    # base case: if a target is found
    if target == 0:
        return 1
 
    # base case: no elements are left
    if n < 0:
        return 0
 
    # 1. ignore the current element
    exclude = countWays(A,n - 1,target)
 
    # 2. Consider the current element
    #    2.1. Subtract the current element from the target
    #    2.2. Add the current element to the target
    include = countWays(A,target - A[n]) + countWays(A,target + A[n])
 
    # Return total count
    return exclude + include
 
 
if __name__ == '__main__':
 
    # input list and target number
    A = [5,-6,2]
    target = 6
 
    print(countWays(A,len(A) - 1,target),"ways")

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?