我有一个关于硬币变化问题的问题,我们不仅需要打印用给定硬币面额更改$ n的方法的数量,例如{1,5,10,25},而且还打印方式< / p>
例如,如果目标= $ 50,而硬币是{1,5,10,25}
,那么实际使用硬币获取目标的方法是
解决此问题的最佳时间复杂度是多少? 我尝试修改硬币更改问题的动态编程解决方案,我们只需要多种方式而不是实际方式
我无法弄清楚时间的复杂性。 我确实使用了记忆,因此我不必为给定的硬币和总和值再次解决同样的问题,但我们仍需要遍历所有解决方案并打印它们。所以时间复杂度绝对超过O(ns),其中n是硬币数,s是目标 它是指数吗?任何帮助将不胜感激
答案 0 :(得分:1)
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]]
没有:我们不需要使用最后一个硬币来计算总和。通过递归solution[s][n-1]
直接找到所有硬币解决方案。我们将所有这些硬币组合复制到with_last_sols
。
:我们做需要使用最后一枚硬币。所以硬币必须在我们的解决方案中。其余硬币通过sol[s - coins[n - 1]][n]
递归发现。阅读此条目将为我们提供许多可能的选择,以确定剩余的硬币应该是什么。对于每个可能的选择sol
,我们附加最后一枚硬币coin[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 solutions ,等于s的integer partitions的数量,p (S)。 可以看出,整数分区的数量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)时间。 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)空间。
答案 1 :(得分:0)
让d_i为面额,硬币的价值为美分。在你的例子中,d_i = {1,5,10,25}。 设k是面额(硬币)的数量,这里k = 4。
我们将使用2D数组numberOfCoins [1..k] [0..n]来确定进行更改所需的硬币的最小数量。最佳解决方案由:
给出numberOfCoins[k][n] = min(numberOfCoins[i − 1][j], numberOfCoins[i][j − d_i] + 1)
上面的等式代表了这样一个事实,即要建立一个最优解,我们要么不使用d_i,所以我们需要使用一个较小的硬币(这就是我在下面递减的原因):
numberOfCoins[i][j] = numberOfCoins[i − 1][j] // eq1
或者我们使用d_i,所以我们在所需的硬币数量上加+1,然后减去d_i(我们刚才使用的硬币的价值):
numberOfCoins[i][j] = numberOfCoins[i][j − d_i] + 1 // eq2
时间复杂度为O(kn),但在k很小的情况下,如示例中的情况,我们有O(4n)= O(n)。
我们将使用另一个2D数组,coinUsed,与numberOfCoins具有相同的尺寸,以标记使用了哪些硬币。每个条目要么告诉我们,我们没有在coinUsed [i] [j]中使用硬币,通过设置&#34; ^&#34;在那个位置(这对应于eq1)。或者我们通过设置&#34;&lt;&#34;来标记硬币的使用。在那个位置(对应于eq2)。
可以在算法运行时构建两个阵列。我们在内循环中只会有更多的指令,因此构建两个数组的时间复杂度仍为O(kn)。
要打印解决方案,我们需要迭代,在更糟糕的情况下,通过k + n + 1个元素。例如,当最优解决方案使用所有1美分面额时。但请注意,打印是在构建之后完成的,因此总体时间复杂度为O(kn)+ O(k + n + 1)。如前所述,如果k很小,则复杂度为O(kn)+ O(k + n + 1)= O(kn)+ O(n + 1)= O(kn)+ O(n)= O((k +1)n)= O(n)。
答案 2 :(得分:0)
我倾向于以递归方式解决问题,然后从那里构建一个memoization解决方案。
从递归的方法开始,方法很简单,从目标中选择硬币减去并且不要选择硬币。
当你选择一枚硬币时,你可以将它添加到矢量或列表中,当你不选择一枚硬币时,你可以弹出之前添加的硬币。代码看起来像:
void print(vector<int>& coinsUsed)
{
for(auto c : coinsUsed)
{
cout << c << ",";
}
cout << endl;
}
int helper(vector<int>& coins, int target, int index, vector<int>& coinsUsed)
{
if (index >= coins.size() || target < 0) return 0;
if (target == 0)
{
print(coinsUsed);
return 1;
}
coinsUsed.push_back(coins[index]);
int with = helper(coins, target - coins[index], index, coinsUsed);
coinsUsed.pop_back();
int without = helper(coins, target, index + 1, coinsUsed);
return with + without;
}
int coinChange(vector<int>& coins, int target)
{
vector<int> coinsUsed;
return helper(coins, target, 0, coinsUsed);
}
你可以这样称呼:
vector<int> coins = {1,5,10,25};
cout << "Total Ways:" << coinChange(coins, 10);
因此,这为您提供了总计方式以及在此过程中使用的硬币,以便达到coinsUsed
中存储的目标,您现在可以通过将传入的值存储在缓存中来随意记忆。
递归解的时间复杂度是指数级的。
链接到正在运行的程序:http://coliru.stacked-crooked.com/a/5ef0ed76b7a496fe