3 回答
TA贡献1796条经验 获得超7个赞
您可以使用从当前货币中扣除的每个硬币进行递归调用,并从调用的返回值中获取最小值。如果扣除导致货币小于 0,则返回无穷大,这样它就不会被认为是可行的:
def findMinCoins(money, coins):
if money < 0:
return float('inf')
return money and min(findMinCoins(money - coin, coins) for coin in coins) + 1
以便:
findMinCoins(55, [25, 10, 1])
返回:
4
然而,上面的递归很慢,因为在考虑不同的路径时,它会以相同的金额进行大量调用。您可以通过使用 dict 作为缓存来记忆给定金额和硬币组合的结果,从而显着提高性能:
def findMinCoins(money, coins, cache={}):
key = money, tuple(coins)
if key in cache:
return cache[key]
if money < 0:
number = float('inf')
else:
number = money and min(findMinCoins(money - coin, coins) for coin in coins) + 1
cache[key] = number
return number
TA贡献1789条经验 获得超10个赞
从字面上重写你的for循环:
>>> money=55
>>> lst=[(q+d+c, [q,d,c]) for q in range(int(money/25)+1) for d in range(int(money/10)+1) for c in range(int(money/1)+1) if q*25 + d*10 + c == money]
>>> lst
[(55, [0, 0, 55]), (46, [0, 1, 45]), (37, [0, 2, 35]), (28, [0, 3, 25]), (19, [0, 4, 15]), (10, [0, 5, 5]), (31, [1, 0, 30]), (22, [1, 1, 20]), (13, [1, 2, 10]), (4, [1, 3, 0]), (7, [2, 0, 5])]
然后找到最合适的:
>>> list(filter(lambda x: x[0]==min(el[0] for el in lst), lst))
[(4, [1, 3, 0])]
- - - - - - -编辑
概括解决方案:
>>> import itertools
>>> money=55
>>> coins=[25,10,1]
>>> lst=[(len(el), el) for num in range(1, money//min(coins)+1) for el in itertools.combinations_with_replacement(coins, num) if sum(el) == money]
>>> lst
[(4, (25, 10, 10, 10)), (7, (25, 25, 1, 1, 1, 1, 1)), (10, (10, 10, 10, 10, 10, 1, 1, 1, 1, 1)), (13, (25, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), (19, (10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), (22, (25, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), (28, (10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), (31, (25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), (37, (10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), (46, (10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), (55, (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))]
>>> list(filter(lambda x: x[0]==min(el[0] for el in lst), lst))
[(4, (25, 10, 10, 10))]
以上内容非常笼统,对于您的问题,尤其是您的硬币中的问题 - 您可能希望通过将潜在硬币数量的上限替换为任何其他正整数1 cent来大大减少计算次数。money//min(coins)+1
例如:
>>> coins=[1,2,5,25,50]
>>> money=100
>>> lst=[(len(el), el) for num in range(1, 5) for el in itertools.combinations_with_replacement(coins, num) if sum(el) == money]
>>> lst
[(2, (50, 50)), (3, (25, 25, 50)), (4, (25, 25, 25, 25))]
>>> list(filter(lambda x: x[0]==min(el[0] for el in lst), lst))
[(2, (50, 50))]
TA贡献1853条经验 获得超6个赞
可能有一种更 Pythonic 的方式来做到这一点,但一般的递归方法是这样做的:
取剩余的金额尝试对每个硬币进行递归调用,以减少金额而不会变为负数。取该集合中最小的结果
def findMinCoins(money, coins):
if money <= 0:
return 0
results = []
for c in coins:
if money >= c:
results.append(1 + findMinCoins(money-c, coins))
results.sort()
return results[0] #return the smallest result
现在上面唯一的问题是它非常慢,因为它会对先前计算的值进行大量冗余调用。因此,我们将对其进行修改,以便为每个最终结果提供一个查找表,并以递归方式传递。
def findMinCoins(money, coins, lookup):
if money <= 0:
return 0
if money in lookup:
return lookup[money]
results = []
for c in coins:
if money >= c:
results.append(1 + findMinCoins(money-c, coins, lookup))
results.sort()
best = results[0]
lookup[money] = best
return best
测试一些例子:
>>> findMinCoins(95,[25,10,5,1], {})
5
>>> findMinCoins(4,[25,10,5,1], {})
4
>>> findMinCoins(44,[25,10,5,1], {})
7
添加回答
举报