Python 递归调用函数

Python 递归调用函数,python,recursion,Python,Recursion,我有10、20、50张钞票,当我需要支付任何金额时,我需要找到最佳组合。因此,例如,当我需要支付7时,我将支付5和2的票据 我有一个函数可以计算这个。但我需要运行相同的函数3或4次,如下所示。如何递归调用该函数 my_dir={} import bisect def my_change(my_amount): c=[1,2,5,10,20,50,100,500] my_pos=bisect.bisect(c, my_amount) my_val=c[my_pos-1]

我有10、20、50张钞票,当我需要支付任何金额时,我需要找到最佳组合。因此,例如,当我需要支付7时,我将支付5和2的票据

我有一个函数可以计算这个。但我需要运行相同的函数3或4次,如下所示。如何递归调用该函数

my_dir={}
import bisect
def my_change(my_amount):
    c=[1,2,5,10,20,50,100,500]
    my_pos=bisect.bisect(c, my_amount)
    my_val=c[my_pos-1]
    my_num=my_amount//my_val
    my_recurr=my_amount-(my_num*c[my_pos-1])
    my_dir[my_val] = my_num
    return my_recurr
有没有更好的计算方法

my_change(417)
17

my_change(17)
7

my_change(7)
2

my_change(2)
0

my_dir
{2: 1, 5: 1, 10: 1, 100: 4}

更新:

根据可用的内容,组合可能会发生变化

available_cash={1:20, 2:10, 10:100, 50:100, 100:1, 500:1}
应导致以下情况:

actual_pay={1:1, 2: 3, 10: 1, 50:6, 100: 1}

更新:

有没有更好的编码方法

amt=417
my_dict={}
available_cash={1:20, 2:10, 10:100, 50:100, 100:1, 500:1}
new_list=sorted(available_cash, reverse=True)

for key in new_list:
    if amt >= key * available_cash[key]:
        my_dict[key] = available_cash[key]
        amt = amt - (key * available_cash[key])
    else:
        if amt >= key:
            notes = amt // key
            amt = amt - (key * notes)
            my_dict[key] = notes

更新1:

如果我需要在付款后找到留在ATM机上的钞票,我可以使用柜台

from collections import Counter
A = Counter(available_cash)
B = Counter(my_dict)

A - B
Counter({10: 99, 50: 94, 1: 19, 2: 7, 500: 1})

您可以使用以下内容:

my_dir = {}
change = 417
def my_change(my_amount):
    # Your function code here
while change > 0:
    change = my_change(change)
但实际上,您的代码可以简化,递归的解决方案是:

def my_change(amount, i=None):
    c = [1, 2, 5, 10, 20, 50, 100, 500]
    if i is None:
        i = len(c) - 1
    note = c[i]
    n, rest = divmod(amount, note)
    result = {}
    if n > 0:
        result[note] = n
    if rest > 0:
        result.update(my_change(rest, i - 1))
    return result

不需要对分或复杂的计算。

您甚至不需要使用递归,您可以在一段时间内进行换行,因此它将继续计算,直到更改为0,基本上与手动操作相同,但只需运行1次:

my_dir={}
import bisect
def my_change(my_amount):
    my_dict={}
    c=[1,2,5,10,20,50,100,500]
    while (my_amount > 0 ):
        my_pos=bisect.bisect(c, my_amount)
        my_val=c[my_pos-1]
        my_num=my_amount//my_val
        my_recurr=my_amount-(my_num*c[my_pos-1])
        my_dir[my_val] = my_num
        my_amount = my_recurr
    return my_dir

如果你坚持递归地做,你可以使用一个小的helper函数来做,这个函数调用自己的数量会越来越少(直到它达到零),传递自己到目前为止使用的注释集。像

import collections

notes = [500, 100, 50, 20, 10, 5, 2, 1]

def my_change(amount):
    def go(amount, notesUsed):
        if amount <= 0:
            return notesUsed
        largestNote = next(x for x in notes if x <= amount)
        notesUsed[largestNote] += 1
        return go(amount - largestNote, notesUsed)

    return go(amount, collections.defaultdict(int))
导入集合
注=[500,100,50,20,10,5,2,1]
def my_找零(金额):
def go(金额、使用的票据):

如果数量在Python中不鼓励递归。Python不能优化递归,它限制了递归调用的最大深度(尽管这个限制可以修改)。这个特定的应用程序不会深入递归,但最好避免Python中的递归,除非它适合这个问题,例如遍历树结构

这个问题可以通过迭代很容易地解决,使用a(对于与金钱相关的任务来说有多合适:))。在每个阶段,只需删除低于当前数量的最高音符的倍数

例如:

#!/usr/bin/env python

all_notes = [1, 2, 5, 10, 20, 50, 100, 500]

def my_change(amount):
    my_notes = list(all_notes)

    change = {}
    print amount
    while amount > 0:
        while my_notes[-1] > amount:
            my_notes.pop()
        note = my_notes[-1]
        num, amount = divmod(amount, note)
        print '%d x %d = %d, %d' % (num, note, num * note, amount)
        change[note] = num
    return change

print my_change(9)
print my_change(26)
print my_change(873)
输出

9
1 x 5 = 5, 4
2 x 2 = 4, 0
{2: 2, 5: 1}
26
1 x 20 = 20, 6
1 x 5 = 5, 1
1 x 1 = 1, 0
{1: 1, 20: 1, 5: 1}
873
1 x 500 = 500, 373
3 x 100 = 300, 73
1 x 50 = 50, 23
1 x 20 = 20, 3
1 x 2 = 2, 1
1 x 1 = 1, 0
{1: 1, 2: 1, 100: 3, 50: 1, 500: 1, 20: 1}
我在函数中添加了一些
print
语句,这样您就可以了解发生了什么

my_change()
函数的核心是内置的
divmod()
函数,它执行除法,将商和余数作为元组返回
my_change()
还使用
list.pop()
方法从
my_notes
中删除过大的注释,这是
所有注释列表的临时副本

可以很容易地修改此函数,将
my_notes
作为参数,因此,如果由于某种原因无法使用完整的笔记集合,则可以使用此函数



问题中的代码使用
对分
。这对于处理大的排序列表很好,但对于小列表来说太过分了-简单的线性搜索比对分搜索小列表要快。

所以,既然您编辑了这个问题,我们就有了新的要求。
我要建议的代码比你的长一点,但它考虑到你实际上也应该修改可用的现金,因为你是从自动取款机取款的。很明显,取款会降低机器中可用的纸币数量

from collections import OrderedDict

amount = 417
available_cash = OrderedDict((
    (1, 20), (2, 10), (10, 100), (50, 100), (100, 1), (500, 1)
))

def my_change(amount, available_cash):
    change = {}
    for note in reversed(available_cash.keys()):
        note_count = amount / note
        if note_count == 0:
            continue
        elif note_count > available_cash[note]:
            note_count = available_cash[note]
            available_cash[note] = 0
        else:
            available_cash[note] -= note_count
        change[note] = note_count
        amount -= note_count * note
        if amount == 0:
            break
    return change

print my_change(amount, available_cash)
我也放弃了递归函数调用的想法。

stdlib
中的另一个重要内容是
orderedict