【发布时间】:2016-11-20 12:38:19
【问题描述】:
我正在研究一些算法,并遇到了coin change 问题。
在考虑这个问题时,我想出了这个幼稚的递归解决方案:
int coinChange(const vector<int>& coins, int start, int n) {
if (n == 0) return 1;
if (n < 0) return 0;
int total = 0;
for (int i = start; i < coins.size(); ++i) {
if (coins[i] <= n) total += coinChange(coins, i, n-coins[i]);
}
return total;
}
然后我意识到“接受”的解决方案如下:
int count( int S[], int m, int n )
{
// If n is 0 then there is 1 solution (do not include any coin)
if (n == 0)
return 1;
// If n is less than 0 then no solution exists
if (n < 0)
return 0;
// If there are no coins and n is greater than 0, then no solution exist
if (m <=0 && n >= 1)
return 0;
// count is sum of solutions (i) including S[m-1] (ii) excluding S[m-1]
return count( S, m - 1, n ) + count( S, m, n-S[m-1] );
}
起初我以为两者本质上是一样的。我很清楚我的递归树要宽得多,但这似乎只是因为我的算法在每个级别上都做了更多的工作,所以它变得平衡了。看起来这两种算法都在考虑用当前硬币进行更改的方法的数量(假设它 start 与m 在第二个算法中的作用基本相同。
我越看越觉得不管前面的文字,我的算法是O(n^n),第二个是O(2^n)。我已经研究这个太久了,但如果有人能解释一下我的算法与第二个算法相比做了哪些额外的工作,那就太好了。
编辑
我了解这个问题的动态规划解决方案,这个问题纯粹是一个基于复杂性的问题。
【问题讨论】:
-
这可能是题外话,但虽然算法是 O(2^n),但这不是一个严格的界限。也就是说,无论 S[] 的值如何,算法都不是 Theta(2^n)。例如,当 m=2 时,最坏的情况是 S=[1, 2],复杂度是 Theta(Fib(n)) = Theta(phi^n),其中 phi 是黄金分割率。
-
@PaulHankin 好点。所以说这些算法是 Theta(2^n),我的理解是我们实际上需要找到一个
n_sub_0使得 f(n) = O(2^n) 和 f(n) = Omega(2 ^n),对于所有n >= n_sub_0,在这种特殊情况下可以这样做吗? -
Dom,我不确定我明白你在问什么。如果你问是否有可能找到一个常数 c,使得所有大 n 的 c * phi^n >= 2^n,那么证明它不是相对容易。
-
@PaulHankin 对不起,让我试着澄清一下。我想知道是否可以对该算法进行严格限制,使得 f(n) = Theta(x) 或者我们是否可以证明对于大于某个阈值的所有输入,f(n) = Theta(2^ n)。我提出这个是因为您的示例似乎引入了一些小的输入来表明 f(n) = 不是 Theta(2^n) 而是 Theta(phi^n)。我们能否确定在输入什么大小(数组大小和/或更改值)后算法确实是 Theta(2^n)?
-
我相信没有输入是 Theta(2^n),尽管随着硬币数量的增加它越来越接近。我相信(有一些证据,但没有严格的证据)复杂性是 Theta(r^n) 其中 r+r^(-|S|) = 2 and 1
标签: c++ algorithm recursion time-complexity coin-change