题目描述
Implement buy
, which takes a list of required_fruits
(strings), a dictionary prices
(strings for key, positive integers for value), and a total_amount
(integer). It prints all the ways to buy some of each required fruit so that the total price equals total_amount
. You must include at least one of every fruit in required_fruit
and cannot include any other fruits that are not in required_fruit
.
The
display
function will be helpful. You can calldisplay
on afruit
and itscount
to create a string containing both.What does
fruits
andamount
represent? How are they used in the recursive?
def buy(required_fruits, prices, total_amount):
"""Print ways to buy some of each fruit so that the sum of prices is amount.
>>> prices = {'oranges': 4, 'apples': 3, 'bananas': 2, 'kiwis': 9}
>>> buy(['apples', 'oranges', 'bananas'], prices, 12)
[2 apples][1 orange][1 banana]
>>> buy(['apples', 'oranges', 'bananas'], prices, 16)
[2 apples][1 orange][3 bananas]
[2 apples][2 oranges][1 banana]
>>> buy(['apples', 'kiwis'], prices, 36)
[3 apples][3 kiwis]
[6 apples][2 kiwis]
[9 apples][1 kiwi]
"""
def add(fruits, amount, cart):
if fruits == [] and amount == 0:
print(cart)
elif fruits and amount > 0:
fruit = fruits[0]
price = ____
for k in ____:
add(____, ____, ____)
add(required_fruits, total_amount, '')
def display(fruit, count):
"""Display a count of a fruit in square brackets.
>>> display('apples', 3)
'[3 apples]'
>>> display('apples', 1)
'[1 apple]'
"""
assert count >= 1 and fruit[-1] == 's'
if count == 1:
fruit = fruit[:-1] # get rid of the plural s
return '[' + str(count) + ' ' + fruit + ']'
分析
本题要求实现使用字符串列表required_fruits、字典prices(key为字符串,value为正整数)和整数total_amount三个参数的函数buy,buy函数将通过required_fruits查询prices中对应水果的价格,给出总花费为total_amount的所有购买水果的方案(方案要求在required_fruits列表中的水果至少各买一个,不在列表中的水果一个不买)。
根据题目给出的框架,buy函数会使用内部的add函数递归实现。首先分析add函数的行为,它使用fruits(还需要购买的水果列表)、amount(剩余可花费的金额)和cart(当前购买方案)三个参数,进入递归的初始参数为required_fruits、total_amount和''。
add函数的basecase为fruits == 0 and amount == 0,即需要购买的水果都买了且钱全部花完了,此时得到了一个合法的方案cart,函数会print(cart)后结束递归;
然后是非basecase的情况,此时fruits非空且amount > 0,add函数会用变量fruit记录当前需要购买的fruits清单的第一个元素(即水果名字符串),用变量price记录fruit的对应价格。接下来使用for循环,依次递归考虑购买了k个fruit的方案,也就是add(fruits[1:], amount - price * k, cart + display(fruit, k));
最后解释一下这个思路的逻辑以及结束递归的条件,该实现方法每次考虑将一种需要购买的水果以定量的方式加入最终方案中(从最少的1个到最多的当前金钱所能支持的购买的最大数量,用for循环实现,这里只要理解了for循环的功能就可以理解函数的行为了),然后再继续考虑下一种需要购买的水果。递归结束有两种情况,一种是达到basecase,此时需要的水果都购买了且钱都花完了,得到的方案合法,直接将方案打印;第二种是方案不合法,即需要的水果都买了但钱没花完或者需要的水果没买完钱就花完了,此时add函数不会继续递归调用新的add函数,而是不打印非法方案,结束函数。
代码实现
def buy(required_fruits, prices, total_amount):
"""Print ways to buy some of each fruit so that the sum of prices is amount.
>>> prices = {'oranges': 4, 'apples': 3, 'bananas': 2, 'kiwis': 9}
>>> buy(['apples', 'oranges', 'bananas'], prices, 12)
[2 apples][1 orange][1 banana]
>>> buy(['apples', 'oranges', 'bananas'], prices, 16)
[2 apples][1 orange][3 bananas]
[2 apples][2 oranges][1 banana]
>>> buy(['apples', 'kiwis'], prices, 36)
[3 apples][3 kiwis]
[6 apples][2 kiwis]
[9 apples][1 kiwi]
"""
def add(fruits, amount, cart):
if fruits == [] and amount == 0:
print(cart)
elif fruits and amount > 0:
fruit = fruits[0]
price = prices[fruit]
for k in range(1, amount // price + 1):
add(fruits[1:], amount - price * k, cart + display(fruit, k))
add(required_fruits, total_amount, '')
def display(fruit, count):
"""Display a count of a fruit in square brackets.
>>> display('apples', 3)
'[3 apples]'
>>> display('apples', 1)
'[1 apple]'
"""
assert count >= 1 and fruit[-1] == 's'
if count == 1:
fruit = fruit[:-1] # get rid of the plural s
return '[' + str(count) + ' ' + fruit + ']'