这种硬币兑换组合算法的时间复杂度是多少?

时间:2019-05-29 18:17:06

标签: python-3.x algorithm recursion coin-change

您好,我刚刚解决了这个leetcode问题:https://leetcode.com/problems/coin-change-2/

目标是找到coins的不同可能组合的数量,假设每种面额的硬币数量都无限,我们可以用来生成amount

我知道这个问题有一个在O(amount*len(coins))中运行的DP解决方案,我可以在下面的解决方案中添加备注以实现该目的。

但是,我正在努力寻找以下朴素方法的时间复杂度:

def change(amount, coins):
    def helper(amount, coins, id):
        if amount == 0:
            return 1
        res = 0
        for i in range(id, len(coins)):
            if coins[i] <= amount:
                res += helper(amount - coins[i], coins, i)
        return res

    res = helper(amount, coins, 0)
    return res

所以我实际上是在做DFS,在回溯和移动到下一个硬币之前,我会尽量使用第一个硬币。因此,一旦我开始使用下一个硬币,就不能再使用第一个硬币->这样一来,我就可以不计算结果中的排列。

我知道此解决方案的时间复杂度为O(exponential),我也知道它为O(V + E),因为它是DFS。

有人可以给出时间复杂度的确切形式吗?指数项到底是什么?或者如何计算图形中的边和顶点?

2 个答案:

答案 0 :(得分:1)

假设与n相比,数量n很大,每个硬币的值很小,并且硬币阵列的大小为c。实际上,在最坏的情况下,我们可以假设每个硬币的价值约为1。在代表您的解决方案构建的调用堆栈的树中,每个节点将分支c次。树的每一层都从n中减去硬币的值(在最坏的情况下约为1),因此树的深度(或高度)将为n。因此,我们正在看一个高度为n的C分支树。顶点数V = c ^ 0 + c ^ 1 + c ^ 2 + c ^ 3 + ... + c ^(n-1)+ c ^ n。您可以看到该系列简化为here的内容。边数E的计算类似。该算法的时间复杂度为O(c ^ n)。

答案 1 :(得分:0)

这里要注意的几件事

  1. 动态编程是一个概念或想法。它本身不是算法。这是一种用于延长某些算法运行时间的技术,在这些算法中,子问题可能会重叠并使用预先计算的结果。有可能所有子问题都不重叠,这是人们谈论的最坏情况。
  2. 因此,我们假设没有子问题重叠,并且采用自上而下的方法,并且您有 c 1 ,c 2 ,... c n 作为您的硬币面额

认为 ,下面的方法会起作用,

因此自上而下的方法看起来像这样

enter image description here

一些路径将以以0结尾的叶子终止。(该方法产生了初始量 k 的完美分割)。有些没有。

为复杂起见,让我们假设它们都做到了。

因此,在任何给定级别上,您都有 n level_num 个节点。而且您必须遍历树的每个节点。

最长的路径是您不断从初始数量 k 中删除最小面额的地方。 i.i k / c 1

因此,您的情况下的真实时间复杂度为 O(1 + n 1 + n 2 + .... n k / c 1

大多数此类问题的硬币有效面额为1(或其他一些小数),以简化该表达式并使GP易于计算