算法 – 硬币更改(动态编程)

我有一个关于硬币变化问题的问题,我们不仅需要打印用给定硬币面额更改$n的方法的数量,例如{1,5,10,25},而且还打印方式

例如,如果目标= $50,而硬币是{1,5,10,25},那么实际使用硬币获得目标的方法是

> 2×25美元
> 1×25美元2×10美元1×5美元
>等

我们可以解决这个问题的最佳时间复杂度是多少?
我试图修改硬币更改问题的动态编程解决方案,我们只需要多种方式而不是实际方式

我无法搞清楚时间的复杂性.
我确实使用了记忆,因此我不必为给定的硬币和总和值再次解决同样的问题,但我们仍需要遍历所有解决方案并打印它们.所以时间复杂度绝对超过O(ns),其中n是硬币数,s是目标
它是指数吗?任何帮助都感激不尽

最佳答案 打印组合

def coin_change_solutions(coins, S):
  # create an S x N table for memoization
  N = len(coins)
  sols = [[[] for n in xrange(N + 1)] for s in xrange(S + 1)]
  for n in range(0, N + 1):
    sols[0][n].append([])

  # fill table using bottom-up dynamic programming
  for s in range(1, S+1):
    for n in range(1, N+1):
      without_last = sols[s][n - 1]
      if (coins[n - 1] <= s):
          with_last = [list(sol) + [coins[n-1]] for sol in sols[s - coins[n - 1]][n]]
      else:
          with_last = []
      sols[s][n] = without_last + with_last

  return sols[S][N]


print coin_change_solutions([1,2], 4)
# => [[1, 1, 1, 1], [1, 1, 2], [2, 2]]

>没有:我们不需要使用最后一枚硬币来计算总和.通过递归到解决方案[s] [n-1]直接找到所有硬币解决方案.我们将所有这些硬币组合复制到with_last_sols.
> with:我们确实需要使用最后一枚硬币.所以硬币必须在我们的解决方案中.其余的硬币通过sol [s – coins [n – 1]] [n]递归地找到.阅读此条目将为我们提供许多可能的选择,以确定剩余的硬币应该是什么.对于每个可能的选择,sol,我们附加最后一枚硬币,硬币[n – 1]:

   

# For example, suppose target is s = 4
# We're finding solutions that use the last coin.
# Suppose the last coin has a value of 2:
#
# find possible combinations that add up to 4 - 2 = 2: 
# ===> [[1,1], [2]] 
# then for each combination, add the last coin 
# so that the combination adds up to 4)
# ===> [[1,1,2], [2,2]]

通过采用第一种情况和第二种情况的组合并连接两个列表,找到最终的组合列表.

without_last_sols = [[1,1,1,1]]
with_last_sols = [[1,1,2], [2,2]]
without_last_sols + with_last_sols = [[1,1,1,1], [1,1,2], [2,2]]

时间复杂性

在最坏的情况下,我们有一个硬币套装,所有硬币从1到n:硬币
 = [1,2,3,4,…,n] – 可能的硬币和组合的数量,num解决方案,等于s,p(s)的integer partitions的数量.
可以看出,整数分区的数量p(s)增长为exponentially.
因此,num solutions = p(s)= O(2 ^ s).任何解决方案必须至少具有此功能,以便它可以打印出所有这些可能的解决方案.因此,问题本质上是指数级的.

我们有两个循环:一个循环用于s,另一个循环用于n.
对于每个s和n,我们计算sols [s] [n]:

>不:我们在sol [s – coins [n – 1]] [n]中查看O(2 ^ s)组合.对于每种组合,我们在O(n)时间内复制它.总的来说这需要:O(n×2 ^ s)时间.
> with:我们查看sol [s] [n]中的所有O(2 ^ s)组合.对于每个组合列表sol,我们在O(n)时间内创建该新列表的副本,然后附加最后一个硬币.总的来说,这种情况需要O(n×2 ^ s).

因此,时间复杂度为O(s×n)×O(n2 ^ s n2 ^ s)= O(s×n ^ 2×2 ^ s).

空间复杂性

空间复杂度为O(s×n ^ 2×2 ^ s),因为我们有一个s×n表
每个条目存储O(2 ^ s)个可能的组合,(例如[[1,1,1,1],[1,1,2],[2,2]]),每个组合,(例如[1, 1,1,1])取O(n)空间.

点赞