递归调用函数

时间:2015-03-06 11:34:43

标签: 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]
    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:

如果我需要在付款后找到自动柜员机中的留言,我可以使用计数器

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})

5 个答案:

答案 0 :(得分:3)

你甚至不需要使用递归,你可以在一段时间内换行,所以它会一直计算直到变化为0,基本上是你手动做的事情,但只有1次运行:< / p>

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

答案 1 :(得分:0)

您可以使用以下内容:

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

无需bisect或复杂的计算。

答案 2 :(得分:0)

如果你坚持以递归的方式做这件事,你可以使用一个小帮手函数来调用自己,这个函数会以不断减少的量调用自身(直到它达到零),然后传递给目前使用的一组音符。像

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))

go是执行实际递归的本地帮助函数,defaultdict用于计算笔记。

答案 3 :(得分:0)

Python不鼓励递归。 Python无法优化tail-call递归,并且它限制了递归调用的最大深度(尽管可以修改该限制)。这个特定的应用程序不会深度递归,但最好避免Python中的递归,除非它适合于问题,例如走树结构。

这个问题很容易通过迭代来解决,使用greedy algorithm(如何适用于与钱连接的任务:))。在每个阶段,只需删除小于当前数量的最高音符的倍数。

例如:

#!/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过大的注释,all_notesmy_notes列表的临时副本。

修改此函数以将bisect作为参数很容易,因此如果因某些原因无法获得完整的注释,则可以使用它。


问题中的代码使用{{1}}。这对于处理大型排序列表非常有用,但对于小型列表来说这是过度的 - 简单的线性搜索比小型列表的二等分更快。

答案 4 :(得分:0)

所以,既然你已经编辑了这个问题,我们就有了新的要求 我要提出的代码比你的代码要长一些,但是考虑到你实际上也应该修改available_cash,因为你是从ATM取钱的。很明显,取款会使机器中可用的纸币数量减少。

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中另一个重要的事情是OrderedDict类。