如果每枚硬币的数量不受限制,则复杂度为O(n*m)
,其中n
为总变化,m
为硬币类型数。现在,当每种类型的硬币都有限时,我们必须考虑剩余的硬币。我设法使用O(n*m2)
的复杂度使用另一个n
,因此我可以跟踪每种类型的剩余硬币。是否有一种方法可以使复杂性更好?编辑:问题是计算进行确切给定更改所需的硬币数量最少以及我们使用每种硬币类型的次数
答案 0 :(得分:2)
不需要额外的循环。你需要:
以下是Python 3中代码的外观:
def getChange(coins, amount, coinIndex = 0):
if amount == 0:
return [] # success
if coinIndex >= len(coins):
return None # failure
coin = coins[coinIndex]
coinIndex += 1
# Start by taking as many as possible from this coin
canTake = min(amount // coin["value"], coin["count"])
# Reduce the number taken from this coin until success
for count in range(canTake, -1, -1): # count will go down to zero
# Recurse to decide how many to take from the next coins
change = getChange(coins, amount - coin["value"] * count, coinIndex)
if change != None: # We had success
if count: # Register this number for this coin:
return change + [{ "value": coin["value"], "count": count }]
return change
# Example data and call:
coins = [
{ "value": 20, "count": 2 },
{ "value": 10, "count": 2 },
{ "value": 5, "count": 3 },
{ "value": 2, "count": 2 },
{ "value": 1, "count": 10 }
]
result = getChange(coins, 84)
print(result)
给定示例的输出:
[
{'value': 1, 'count': 5},
{'value': 2, 'count': 2},
{'value': 5, 'count': 3},
{'value': 10, 'count': 2},
{'value': 20, 'count': 2}
]
如评论中所述,上述算法返回它找到的第一个解决方案。如果要求在有多个解决方案时必须最小化单个硬币的数量,那么您不能return
中途循环,但必须保留到目前为止找到的“最佳”解决方案。
以下是修改后的代码:
def getchange(coins, amount):
minCount = None
def recurse(amount, coinIndex, coinCount):
nonlocal minCount
if amount == 0:
if minCount == None or coinCount < minCount:
minCount = coinCount
return [] # success
return None # not optimal
if coinIndex >= len(coins):
return None # failure
bestChange = None
coin = coins[coinIndex]
# Start by taking as many as possible from this coin
cantake = min(amount // coin["value"], coin["count"])
# Reduce the number taken from this coin until 0
for count in range(cantake, -1, -1):
# Recurse, taking out this coin as a possible choice
change = recurse(amount - coin["value"] * count, coinIndex + 1,
coinCount + count)
# Do we have a solution that is better than the best so far?
if change != None:
if count: # Does it involve this coin?
change.append({ "value": coin["value"], "count": count })
bestChange = change # register this as the best so far
return bestChange
return recurse(amount, 0, 0)
coins = [{ "value": 10, "count": 2 },
{ "value": 8, "count": 2 },
{ "value": 3, "count": 10 }]
result = getchange(coins, 26)
print(result)
输出:
[
{'value': 8, 'count': 2},
{'value': 10, 'count': 1}
]
答案 1 :(得分:0)
这是Python中O(nm)解决方案的实现。
如果定义C(c, k) = 1 + x^c + x^(2c) + ... + x^(kc)
,则程序计算多项式n+1
的第一个product(C(c[i], k[i]), i = 1...ncoins)
系数。此多项式的j
系数是j
进行更改的方式数。
当所有k
s都不受限制时,此多项式乘积很容易计算(例如,参见:https://stackoverflow.com/a/20743780/1400793)。当受限时,需要能够有效地计算k
项的运行总和,这是使用rs
数组在程序中完成的。
# cs is a list of pairs (c, k) where there's k
# coins of value c.
def limited_coins(cs, n):
r = [1] + [0] * n
for c, k in cs:
# rs[i] will contain the sum r[i] + r[i-c] + r[i-2c] + ...
rs = r[:]
for i in xrange(c, n+1):
rs[i] += rs[i-c]
# This line effectively performs:
# r'[i] = sum(r[i-j*c] for j=0...k)
# but using rs[] so that the computation is O(1)
# and in place.
r[i] += rs[i-c] - (0 if i<c*(k+1) else rs[i-c*(k+1)])
return r[n]
for n in xrange(50):
print n, limited_coins([(1, 3), (2, 2), (5, 3), (10, 2)], n)